@Override
  public List<ObjectAction> getObjectActions(
      final List<ActionType> types,
      final Contributed contributed,
      final Filter<ObjectAction> filter) {

    // update our list of actions if requesting for contributed actions
    // and they have not yet been added
    // the "contributed.isIncluded()" guard is required because we cannot do this too early;
    // there must be a session available
    if (contributed.isIncluded() && !contributeeActionsAdded) {
      synchronized (this.objectActions) {
        final List<ObjectAction> actions = Lists.newArrayList(this.objectActions);
        actions.addAll(createContributeeActions());
        sortCacheAndUpdateActions(actions);
        contributeeActionsAdded = true;
      }
    }

    final List<ObjectAction> actions = Lists.newArrayList();
    for (final ActionType type : types) {
      final Collection<ObjectAction> filterActions =
          Collections2.filter(objectActionsByType.get(type), Filters.asPredicate(filter));
      actions.addAll(filterActions);
    }
    return Lists.newArrayList(
        Iterables.filter(actions, ContributeeMember.Predicates.regularElse(contributed)));
  }
  private void addContributeeActionsIfAny(
      final ObjectAdapter serviceAdapter, final List<ObjectAction> contributeeActionsToAppendTo) {
    final ObjectSpecification specification = serviceAdapter.getSpecification();
    if (specification == this) {
      return;
    }
    final List<ObjectAction> contributeeActions = Lists.newArrayList();
    final List<ObjectAction> serviceActions =
        specification.getObjectActions(
            ActionType.ALL, Contributed.INCLUDED, Filters.<ObjectAction>any());
    for (final ObjectAction serviceAction : serviceActions) {
      if (isAlwaysHidden(serviceAction)) {
        continue;
      }
      final NotContributedFacet notContributed = serviceAction.getFacet(NotContributedFacet.class);
      if (notContributed != null && notContributed.toActions()) {
        continue;
      }
      if (!(serviceAction instanceof ObjectActionImpl)) {
        continue;
      }
      final ObjectActionImpl contributedAction = (ObjectActionImpl) serviceAction;

      // see if qualifies by inspecting all parameters
      final int contributeeParam = contributeeParameterMatchOf(contributedAction);
      if (contributeeParam != -1) {
        ObjectActionContributee contributeeAction =
            new ObjectActionContributee(
                serviceAdapter, contributedAction, contributeeParam, this, objectMemberContext);
        facetProcessor.processMemberOrder(metadataProperties, contributeeAction);
        contributeeActions.add(contributeeAction);
      }
    }
    contributeeActionsToAppendTo.addAll(contributeeActions);
  }
  protected void sortCacheAndUpdateActions(final List<ObjectAction> objectActions) {
    final List<ObjectAction> orderedActions = sortActions(objectActions);
    synchronized (this.objectActions) {
      this.objectActions.clear();
      this.objectActions.addAll(orderedActions);

      for (final ActionType type : ActionType.values()) {
        final List<ObjectAction> objectActionForType = objectActionsByType.get(type);
        objectActionForType.clear();
        objectActionForType.addAll(
            Collections2.filter(objectActions, ObjectAction.Predicates.ofType(type)));
      }
    }
  }
 private static void sortActions(
     final DeweyOrderSet orderSet, final List<ObjectAction> actionsToAppendTo) {
   for (final Object element : orderSet) {
     if (element instanceof ObjectAction) {
       final ObjectAction objectAction = (ObjectAction) element;
       actionsToAppendTo.add(objectAction);
     } else if (element instanceof DeweyOrderSet) {
       final DeweyOrderSet set = ((DeweyOrderSet) element);
       final List<ObjectAction> actions = Lists.newArrayList();
       sortActions(set, actions);
       actionsToAppendTo.addAll(actions);
     } else {
       throw new UnknownTypeException(element);
     }
   }
 }
 private static void sortAssociations(
     final DeweyOrderSet orderSet, final List<ObjectAssociation> associationsToAppendTo) {
   for (final Object element : orderSet) {
     if (element instanceof OneToManyAssociation) {
       associationsToAppendTo.add((ObjectAssociation) element);
     } else if (element instanceof OneToOneAssociation) {
       associationsToAppendTo.add((ObjectAssociation) element);
     } else if (element instanceof DeweyOrderSet) {
       // just flatten.
       DeweyOrderSet childOrderSet = (DeweyOrderSet) element;
       sortAssociations(childOrderSet, associationsToAppendTo);
     } else {
       throw new UnknownTypeException(element);
     }
   }
 }
 @Override
 public List<ObjectAssociation> getAssociations(final Contributed contributed) {
   // the "contributed.isIncluded()" guard is required because we cannot do this too early;
   // there must be a session available
   if (contributed.isIncluded() && !contributeeAssociationsAdded) {
     synchronized (this.associations) {
       List<ObjectAssociation> associations = Lists.newArrayList(this.associations);
       associations.addAll(createContributeeAssociations());
       sortAndUpdateAssociations(associations);
       contributeeAssociationsAdded = true;
     }
   }
   final List<ObjectAssociation> associations = Lists.newArrayList(this.associations);
   return Lists.newArrayList(
       Iterables.filter(associations, ContributeeMember.Predicates.regularElse(contributed)));
 }
 private void addIfReturnsSubtype(
     final ObjectAction serviceAction,
     final ObjectSpecification actionType,
     final List<ObjectAction> matchingActionsToAppendTo) {
   if (actionType.isOfType(this)) {
     matchingActionsToAppendTo.add(serviceAction);
   }
 }
  protected List<ObjectAssociation> sortAssociations(final List<ObjectAssociation> associations) {
    final DeweyOrderSet orderSet = DeweyOrderSet.createOrderSet(associations);
    final MemberGroupLayoutFacet memberGroupLayoutFacet =
        this.getFacet(MemberGroupLayoutFacet.class);

    if (memberGroupLayoutFacet != null) {
      final List<String> groupOrder = Lists.newArrayList();
      groupOrder.addAll(memberGroupLayoutFacet.getLeft());
      groupOrder.addAll(memberGroupLayoutFacet.getMiddle());
      groupOrder.addAll(memberGroupLayoutFacet.getRight());

      orderSet.reorderChildren(groupOrder);
    }
    final List<ObjectAssociation> orderedAssociations = Lists.newArrayList();
    sortAssociations(orderSet, orderedAssociations);
    return orderedAssociations;
  }
 private void addContributeeAssociationsIfAny(
     final ObjectAdapter serviceAdapter,
     final List<ObjectAssociation> contributeeAssociationsToAppendTo) {
   final ObjectSpecification specification = serviceAdapter.getSpecification();
   if (specification == this) {
     return;
   }
   final List<ObjectAssociation> contributeeAssociations =
       createContributeeAssociations(serviceAdapter);
   contributeeAssociationsToAppendTo.addAll(contributeeAssociations);
 }
 @Override
 public <Q extends Facet> Q getFacet(final Class<Q> facetType) {
   final Q facet = super.getFacet(facetType);
   Q noopFacet = null;
   if (isNotANoopFacet(facet)) {
     return facet;
   } else {
     noopFacet = facet;
   }
   if (interfaces() != null) {
     final List<ObjectSpecification> interfaces = interfaces();
     for (int i = 0; i < interfaces.size(); i++) {
       final ObjectSpecification interfaceSpec = interfaces.get(i);
       if (interfaceSpec == null) {
         // HACK: shouldn't happen, but occurring on occasion when
         // running
         // XATs under JUnit4. Some sort of race condition?
         continue;
       }
       final Q interfaceFacet = interfaceSpec.getFacet(facetType);
       if (isNotANoopFacet(interfaceFacet)) {
         return interfaceFacet;
       } else {
         if (noopFacet == null) {
           noopFacet = interfaceFacet;
         }
       }
     }
   }
   // search up the inheritance hierarchy
   final ObjectSpecification superSpec = superclass();
   if (superSpec != null) {
     final Q superClassFacet = superSpec.getFacet(facetType);
     if (isNotANoopFacet(superClassFacet)) {
       return superClassFacet;
     }
   }
   return noopFacet;
 }
  /**
   * Synthesises {@link ObjectAssociation}s from matching {@link ObjectAction}s of any of the
   * services that accept one parameter
   */
  private List<ObjectAssociation> createContributeeAssociations(
      final ObjectAdapter serviceAdapter) {

    final ObjectSpecification specification = serviceAdapter.getSpecification();
    final List<ObjectAction> serviceActions =
        specification.getObjectActions(
            ActionType.USER, Contributed.INCLUDED, Filters.<ObjectAction>any());

    final List<ObjectActionImpl> contributedActions = Lists.newArrayList();
    for (final ObjectAction serviceAction : serviceActions) {
      if (isAlwaysHidden(serviceAction)) {
        continue;
      }
      final NotContributedFacet notContributed = serviceAction.getFacet(NotContributedFacet.class);
      if (notContributed != null && notContributed.toAssociations()) {
        continue;
      }
      if (!serviceAction.hasReturn()) {
        continue;
      }
      if (serviceAction.getParameterCount() != 1
          || contributeeParameterMatchOf(serviceAction) == -1) {
        continue;
      }
      if (!(serviceAction instanceof ObjectActionImpl)) {
        continue;
      }
      if (!serviceAction.getSemantics().isSafeInNature()) {
        continue;
      }
      contributedActions.add((ObjectActionImpl) serviceAction);
    }

    return Lists.newArrayList(
        Iterables.transform(
            contributedActions, createContributeeAssociationFunctor(serviceAdapter, this)));
  }
 private void appendServiceActionsReturning(
     final ObjectAdapter serviceAdapter,
     final List<ActionType> types,
     final List<ObjectAction> relatedActionsToAppendTo) {
   final List<ObjectAction> matchingActionsToAppendTo = Lists.newArrayList();
   for (final ActionType type : types) {
     final List<ObjectAction> serviceActions =
         serviceAdapter
             .getSpecification()
             .getObjectActions(type, Contributed.INCLUDED, Filters.<ObjectAction>any());
     for (final ObjectAction serviceAction : serviceActions) {
       addIfReturnsSubtype(serviceAction, matchingActionsToAppendTo);
     }
   }
   relatedActionsToAppendTo.addAll(matchingActionsToAppendTo);
 }
 public boolean hasSubclasses() {
   return !classes.isEmpty();
 }
 public void addSubclass(final ObjectSpecification subclass) {
   if (classes.contains(subclass)) {
     return;
   }
   classes.add(subclass);
 }