/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.isis.core.metamodel.specloader.specimpl; import java.util.Arrays; import java.util.List; import com.google.common.collect.Lists; import org.apache.isis.applib.Identifier; import org.apache.isis.applib.annotation.Where; import org.apache.isis.applib.filter.Filter; import org.apache.isis.core.metamodel.adapter.ObjectAdapter; import org.apache.isis.core.metamodel.consent.Consent; import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy; import org.apache.isis.core.metamodel.facetapi.Facet; import org.apache.isis.core.metamodel.facetapi.FacetHolder; import org.apache.isis.core.metamodel.facetapi.FacetHolderImpl; import org.apache.isis.core.metamodel.facetapi.FacetUtil; import org.apache.isis.core.metamodel.facetapi.FeatureType; import org.apache.isis.core.metamodel.facetapi.MultiTypedFacet; import org.apache.isis.core.metamodel.facets.FacetedMethodParameter; import org.apache.isis.core.metamodel.facets.TypedHolder; import org.apache.isis.core.metamodel.interactions.InteractionUtils; import org.apache.isis.core.metamodel.interactions.UsabilityContext; import org.apache.isis.core.metamodel.interactions.VisibilityContext; import org.apache.isis.core.metamodel.services.ServicesInjector; import org.apache.isis.core.metamodel.spec.ObjectSpecification; import org.apache.isis.core.metamodel.spec.feature.ObjectAction; import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter; public class ObjectActionContributee extends ObjectActionDefault implements ContributeeMember2 { private final Object servicePojo; private final ObjectActionDefault serviceAction; private final int contributeeParam; private final ObjectSpecification contributeeType; /** * Hold facets rather than delegate to the contributed action (different types might * use layout metadata to position the contributee in different ways) */ private final FacetHolder facetHolder = new FacetHolderImpl(); private final Identifier identifier; public ObjectActionContributee( final Object servicePojo, final ObjectActionDefault serviceAction, final int contributeeParam, final ObjectSpecification contributeeType, final ServicesInjector servicesInjector) { super(serviceAction.getFacetedMethod(), servicesInjector); this.servicePojo = servicePojo; this.serviceAction = serviceAction; this.contributeeType = contributeeType; this.contributeeParam = contributeeParam; // copy over facets from contributed to own. FacetUtil.copyFacets(serviceAction.getFacetedMethod(), facetHolder); // calculate the identifier final Identifier contributorIdentifier = serviceAction.getFacetedMethod().getIdentifier(); final String memberName = contributorIdentifier.getMemberName(); List<String> memberParameterNames = contributorIdentifier.getMemberParameterNames(); identifier = Identifier.actionIdentifier(getOnType().getCorrespondingClass().getName(), memberName, memberParameterNames); } @Override public ObjectSpecification getOnType() { return contributeeType; } public int getParameterCount() { return serviceAction.getParameterCount() - 1; } public int getContributeeParam() { return contributeeParam; } @Override public boolean isContributedBy(final ObjectAction serviceAction) { return serviceAction == this.serviceAction; } @Override public int getContributeeParamPosition() { return contributeeParam; } @Override protected synchronized List<ObjectActionParameter> determineParameters() { if (parameters != null) { // because possible race condition (caller isn't synchronized) return parameters; } final List<ObjectActionParameter> serviceParameters = serviceAction.getParameters(); final List<FacetedMethodParameter> paramPeers = getFacetedMethod().getParameters(); final List<ObjectActionParameter> contributeeParameters = Lists.newArrayList(); int contributeeParamNum = 0; for (int serviceParamNum = 0; serviceParamNum < serviceParameters.size(); serviceParamNum++ ) { if(serviceParamNum == contributeeParam) { // skip so is omitted from the Contributed action continue; } final TypedHolder paramPeer = paramPeers.get(serviceParamNum); final ObjectSpecification specification = ObjectMemberAbstract .getSpecification(getSpecificationLoader(), paramPeer.getType()); final ObjectActionParameterAbstract serviceParameter = (ObjectActionParameterAbstract) serviceParameters.get(serviceParamNum); final ObjectActionParameterContributee contributedParam = serviceParameter.getPeer().getFeatureType() == FeatureType.ACTION_PARAMETER_SCALAR ? new OneToOneActionParameterContributee( getServiceAdapter(), serviceParameter, contributeeParamNum, this) : new OneToManyActionParameterContributee( getServiceAdapter(), serviceParameter, contributeeParamNum, this); contributeeParameters.add(contributedParam); contributeeParamNum++; } return contributeeParameters; } @Override public Consent isVisible( final ObjectAdapter contributee, final InteractionInitiatedBy interactionInitiatedBy, Where where) { final VisibilityContext<?> ic = serviceAction.createVisibleInteractionContext(getServiceAdapter(), interactionInitiatedBy, where); ic.putContributee(this.contributeeParam, contributee); return InteractionUtils.isVisibleResult(this, ic).createConsent(); } @Override public Consent isUsable( final ObjectAdapter contributee, final InteractionInitiatedBy interactionInitiatedBy, final Where where) { final UsabilityContext<?> ic = serviceAction.createUsableInteractionContext(getServiceAdapter(), interactionInitiatedBy, where); ic.putContributee(this.contributeeParam, contributee); return InteractionUtils.isUsableResult(this, ic).createConsent(); } @Override public ObjectAdapter[] getDefaults(final ObjectAdapter target) { final ObjectAdapter[] contributorDefaults = serviceAction.getDefaults(getServiceAdapter()); return removeElementFromArray(contributorDefaults, contributeeParam, new ObjectAdapter[]{}); } @Override public ObjectAdapter[][] getChoices( final ObjectAdapter target, final InteractionInitiatedBy interactionInitiatedBy) { final ObjectAdapter[][] serviceChoices = serviceAction.getChoices(getServiceAdapter(), interactionInitiatedBy); return removeElementFromArray(serviceChoices, contributeeParam, new ObjectAdapter[][]{}); } public Consent isProposedArgumentSetValid( final ObjectAdapter contributee, final ObjectAdapter[] proposedArguments, final InteractionInitiatedBy interactionInitiatedBy) { ObjectAdapter[] serviceArguments = argsPlusContributee(contributee, proposedArguments); return serviceAction.isProposedArgumentSetValid(getServiceAdapter(), serviceArguments, interactionInitiatedBy); } @Override public ObjectAdapter execute( final ObjectAdapter targetAdapter, final ObjectAdapter mixedInAdapter, final ObjectAdapter[] argumentAdapters, final InteractionInitiatedBy interactionInitiatedBy) { setupCommand(targetAdapter, argumentAdapters); return serviceAction.executeInternal( getServiceAdapter(), mixedInAdapter, argsPlusContributee(targetAdapter, argumentAdapters), interactionInitiatedBy); } private ObjectAdapter[] argsPlusContributee(final ObjectAdapter contributee, final ObjectAdapter[] arguments) { return addElementToArray(arguments, contributeeParam, contributee, new ObjectAdapter[]{}); } // ////////////////////////////////////// // FacetHolder // ////////////////////////////////////// @Override public Class<? extends Facet>[] getFacetTypes() { return facetHolder.getFacetTypes(); } @Override public <T extends Facet> T getFacet(Class<T> cls) { return facetHolder.getFacet(cls); } @Override public boolean containsFacet(Class<? extends Facet> facetType) { return facetHolder.containsFacet(facetType); } @Override public boolean containsDoOpFacet(java.lang.Class<? extends Facet> facetType) { return facetHolder.containsDoOpFacet(facetType); } @Override public List<Facet> getFacets(Filter<Facet> filter) { return facetHolder.getFacets(filter); } @Override public void addFacet(Facet facet) { facetHolder.addFacet(facet); } @Override public void addFacet(MultiTypedFacet facet) { facetHolder.addFacet(facet); } @Override public void removeFacet(Facet facet) { facetHolder.removeFacet(facet); } @Override public void removeFacet(Class<? extends Facet> facetType) { facetHolder.removeFacet(facetType); } // ////////////////////////////////////// /* (non-Javadoc) * @see org.apache.isis.core.metamodel.specloader.specimpl.ObjectMemberAbstract#getIdentifier() */ @Override public Identifier getIdentifier() { return identifier; } // ////////////////////////////////////// static <T> T[] addElementToArray(T[] array, final int n, final T element, final T[] type) { List<T> list = Lists.newArrayList(Arrays.asList(array)); list.add(n, element); return list.toArray(type); } static <T> T[] removeElementFromArray(T[] array, int n, T[] t) { List<T> list = Lists.newArrayList(Arrays.asList(array)); list.remove(n); return list.toArray(t); } public ObjectAdapter getServiceAdapter() { return getPersistenceSessionService().adapterFor(servicePojo); } @Override public ObjectSpecification getServiceContributedBy() { return getServiceAdapter().getSpecification(); } }