/** * 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.List; import com.google.common.base.Strings; import com.google.common.collect.Lists; import org.apache.isis.applib.Identifier; import org.apache.isis.applib.annotation.Where; 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.consent.InteractionResultSet; 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.facets.FacetedMethodParameter; import org.apache.isis.core.metamodel.facets.TypedHolder; import org.apache.isis.core.metamodel.facets.all.named.NamedFacetInferred; import org.apache.isis.core.metamodel.interactions.InteractionUtils; import org.apache.isis.core.metamodel.interactions.UsabilityContext; import org.apache.isis.core.metamodel.interactions.ValidityContext; 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 ObjectActionMixedIn extends ObjectActionDefault implements MixedInMember2 { /** * The type of the mixin (providing the action), eg annotated with {@link org.apache.isis.applib.annotation.Mixin}. */ private final Class<?> mixinType; /** * The {@link ObjectActionDefault} for the action being mixed in (ie on the {@link #mixinType}. */ final ObjectActionDefault mixinAction; /** * The domain object type being mixed in to (being supplemented). */ private final ObjectSpecification mixedInType; /** * Hold facets rather than delegate to the mixin action */ private final FacetHolder facetHolder = new FacetHolderImpl(); /** * Lazily initialized by {@link #getParameters()} (so don't use directly!) */ private List<ObjectActionParameter> parameters; private final Identifier identifier; public ObjectActionMixedIn( final Class<?> mixinType, final String mixinMethodName, final ObjectActionDefault mixinAction, final ObjectSpecification mixedInType, final ServicesInjector objectMemberDependencies) { super(mixinAction.getFacetedMethod(), objectMemberDependencies); this.mixinType = mixinType; this.mixinAction = mixinAction; this.mixedInType = mixedInType; // copy over facets from mixin action to self FacetUtil.copyFacets(mixinAction.getFacetedMethod(), facetHolder); // adjust name if necessary final String name = getName(); if(Strings.isNullOrEmpty(name) || name.equalsIgnoreCase(mixinMethodName)) { String memberName = determineNameFrom(mixinAction); FacetUtil.addFacet(new NamedFacetInferred(memberName, facetHolder)); } // calculate the identifier final Identifier mixinIdentifier = mixinAction.getFacetedMethod().getIdentifier(); List<String> memberParameterNames = mixinIdentifier.getMemberParameterNames(); identifier = Identifier.actionIdentifier(getOnType().getCorrespondingClass().getName(), getId(), memberParameterNames); } @Override public String getId() { return determineIdFrom(this.mixinAction); } @Override public String getOriginalId() { return super.getId(); } public boolean hasMixinAction(final ObjectAction mixinAction) { return this.mixinAction == mixinAction; } @Override public ObjectSpecification getOnType() { return mixedInType; } public int getParameterCount() { return mixinAction.getParameterCount(); } @Override protected synchronized List<ObjectActionParameter> determineParameters() { if (parameters != null) { // because possible race condition (caller isn't synchronized) return parameters; } final List<ObjectActionParameter> mixinActionParameters = mixinAction.getParameters(); final List<FacetedMethodParameter> paramPeers = getFacetedMethod().getParameters(); final List<ObjectActionParameter> mixedInParameters = Lists.newArrayList(); for(int paramNum = 0; paramNum < mixinActionParameters.size(); paramNum++) { final ObjectActionParameterAbstract mixinParameter = (ObjectActionParameterAbstract) mixinActionParameters.get(paramNum); final TypedHolder paramPeer = paramPeers.get(paramNum); final ObjectSpecification specification = ObjectMemberAbstract .getSpecification(getSpecificationLoader(), paramPeer.getType()); final ObjectActionParameterMixedIn mixedInParameter = mixinParameter.getPeer().getFeatureType() == FeatureType.ACTION_PARAMETER_SCALAR ? new OneToOneActionParameterMixedIn(mixinParameter, this) : new OneToManyActionParameterMixedIn(mixinParameter, this); mixedInParameters.add(mixedInParameter); } return mixedInParameters; } @Override public Consent isVisible( final ObjectAdapter mixedInAdapter, final InteractionInitiatedBy interactionInitiatedBy, final Where where) { final ObjectAdapter mixinAdapter = mixinAdapterFor(mixinType, mixedInAdapter); final VisibilityContext<?> ic = mixinAction.createVisibleInteractionContext(mixinAdapter, interactionInitiatedBy, where); ic.setMixedIn(mixedInAdapter); return InteractionUtils.isVisibleResult(this, ic).createConsent(); } @Override public Consent isUsable( final ObjectAdapter mixedInAdapter, final InteractionInitiatedBy interactionInitiatedBy, final Where where) { final ObjectAdapter mixinAdapter = mixinAdapterFor(mixinType, mixedInAdapter); final UsabilityContext<?> ic = mixinAction.createUsableInteractionContext(mixinAdapter, interactionInitiatedBy, where); ic.setMixedIn(mixedInAdapter); return InteractionUtils.isUsableResult(this, ic).createConsent(); } @Override public ObjectAdapter[] getDefaults(final ObjectAdapter mixedInAdapter) { final ObjectAdapter mixinAdapter = mixinAdapterFor(mixedInAdapter); return mixinAction.getDefaults(mixinAdapter); } @Override public ObjectAdapter[][] getChoices( final ObjectAdapter mixedInAdapter, final InteractionInitiatedBy interactionInitiatedBy) { final ObjectAdapter mixinAdapter = mixinAdapterFor(mixedInAdapter); return mixinAction.getChoices(mixinAdapter, interactionInitiatedBy); } protected ObjectAdapter mixinAdapterFor(final ObjectAdapter mixedInAdapter) { return mixinAdapterFor(mixinType, mixedInAdapter); } @Override protected void validateArgumentSet( final ObjectAdapter mixedInAdapter, final ObjectAdapter[] proposedArguments, final InteractionInitiatedBy interactionInitiatedBy, final InteractionResultSet resultSet) { final ObjectAdapter targetObject = mixinAdapterFor(mixinType, mixedInAdapter); final ValidityContext<?> ic = mixinAction.createActionInvocationInteractionContext(targetObject, proposedArguments, interactionInitiatedBy); ic.setMixedIn(mixedInAdapter); InteractionUtils.isValidResultSet(this, ic, resultSet); } @Override public ObjectAdapter execute( final ObjectAdapter target, // will be the mixedInAdapter final ObjectAdapter mixedInAdapter, // will be passed in as null final ObjectAdapter[] arguments, final InteractionInitiatedBy interactionInitiatedBy) { final ObjectAdapter targetAdapter = mixinAdapterFor(mixinType, target); final ObjectAdapter actualMixedInAdapter = target; setupCommand(actualMixedInAdapter, arguments); return mixinAction.executeInternal( targetAdapter, actualMixedInAdapter, arguments, interactionInitiatedBy); } //region > facetHolder @Override protected FacetHolder getFacetHolder() { return facetHolder; } //endregion /* (non-Javadoc) * @see org.apache.isis.core.metamodel.specloader.specimpl.ObjectMemberAbstract#getIdentifier() */ @Override public Identifier getIdentifier() { return identifier; } @Override public ObjectSpecification getMixinType() { return getSpecificationLoader().loadSpecification(mixinType); } }