001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.isis.core.metamodel.specloader.specimpl; 018 019import java.util.List; 020 021import org.apache.isis.applib.Identifier; 022import org.apache.isis.applib.annotation.Render; 023import org.apache.isis.applib.annotation.When; 024import org.apache.isis.applib.annotation.Where; 025import org.apache.isis.applib.filter.Filter; 026import org.apache.isis.core.commons.authentication.AuthenticationSession; 027import org.apache.isis.core.metamodel.adapter.ObjectAdapter; 028import org.apache.isis.core.metamodel.consent.Consent; 029import org.apache.isis.core.metamodel.consent.InteractionInvocationMethod; 030import org.apache.isis.core.metamodel.facetapi.Facet; 031import org.apache.isis.core.metamodel.facetapi.FacetHolder; 032import org.apache.isis.core.metamodel.facetapi.FacetHolderImpl; 033import org.apache.isis.core.metamodel.facetapi.FacetUtil; 034import org.apache.isis.core.metamodel.facetapi.MultiTypedFacet; 035import org.apache.isis.core.metamodel.facets.members.resolve.RenderFacet; 036import org.apache.isis.core.metamodel.facets.members.resolve.RenderFacetAbstract; 037import org.apache.isis.core.metamodel.facets.notpersisted.NotPersistedFacet; 038import org.apache.isis.core.metamodel.facets.notpersisted.NotPersistedFacetAbstract; 039import org.apache.isis.core.metamodel.facets.typeof.TypeOfFacet; 040import org.apache.isis.core.metamodel.facets.typeof.TypeOfFacetAbstract; 041import org.apache.isis.core.metamodel.interactions.InteractionUtils; 042import org.apache.isis.core.metamodel.interactions.UsabilityContext; 043import org.apache.isis.core.metamodel.interactions.VisibilityContext; 044import org.apache.isis.core.metamodel.spec.ObjectSpecification; 045import org.apache.isis.core.metamodel.spec.SpecificationLoader; 046import org.apache.isis.core.metamodel.spec.feature.ObjectAction; 047import org.apache.isis.core.metamodel.spec.feature.ObjectMemberContext; 048import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacet; 049import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacetImpl; 050import org.apache.isis.core.progmodel.facets.members.resolve.RenderFacetAnnotation; 051 052public class OneToManyAssociationContributee extends OneToManyAssociationImpl implements ContributeeMember { 053 054 private final ObjectAdapter serviceAdapter; 055 private final ObjectAction serviceAction; 056 057 058 /** 059 * Hold facets rather than delegate to the contributed action (different types might 060 * use layout metadata to position the contributee in different ways) 061 */ 062 private final FacetHolder facetHolder = new FacetHolderImpl(); 063 064 private final Identifier identifier; 065 066 private static ObjectSpecification typeOfSpec(final ObjectActionImpl objectAction, ObjectMemberContext objectMemberContext) { 067 final TypeOfFacet actionTypeOfFacet = objectAction.getFacet(TypeOfFacet.class); 068 SpecificationLoader specificationLookup = objectMemberContext.getSpecificationLookup(); 069 // TODO: a bit of a hack; ought really to set up a fallback TypeOfFacetDefault which ensures that there is always 070 // a TypeOfFacet for any contributee associations created from contributed actions. 071 Class<? extends Object> cls = actionTypeOfFacet != null? actionTypeOfFacet.value(): Object.class; 072 return specificationLookup.loadSpecification(cls); 073 } 074 075 public OneToManyAssociationContributee( 076 final ObjectAdapter serviceAdapter, 077 final ObjectActionImpl serviceAction, 078 final ObjectSpecification contributeeType, 079 final ObjectMemberContext objectMemberContext) { 080 super(serviceAction.getFacetedMethod(), typeOfSpec(serviceAction, objectMemberContext), objectMemberContext); 081 this.serviceAdapter = serviceAdapter; 082 this.serviceAction = serviceAction; 083 084 // copy over facets from contributed to own. 085 FacetUtil.copyFacets(serviceAction.getFacetedMethod(), facetHolder); 086 087 final NotPersistedFacet notPersistedFacet = new NotPersistedFacetAbstract(this) {}; 088 final DisabledFacet disabledFacet = disabledFacet(); 089 final TypeOfFacet typeOfFacet = new TypeOfFacetAbstract(getSpecification().getCorrespondingClass(), this, objectMemberContext.getSpecificationLookup()) {}; 090 091 FacetUtil.addFacet(notPersistedFacet); 092 FacetUtil.addFacet(disabledFacet); 093 FacetUtil.addFacet(typeOfFacet); 094 095 // calculate the identifier 096 final Identifier contributorIdentifier = serviceAction.getFacetedMethod().getIdentifier(); 097 final String memberName = contributorIdentifier.getMemberName(); 098 List<String> memberParameterNames = contributorIdentifier.getMemberParameterNames(); 099 100 identifier = Identifier.actionIdentifier(contributeeType.getCorrespondingClass().getName(), memberName, memberParameterNames); 101 } 102 103 private DisabledFacet disabledFacet() { 104 final DisabledFacet originalFacet = facetHolder.getFacet(DisabledFacet.class); 105 if( originalFacet != null && 106 originalFacet.when() == When.ALWAYS && 107 originalFacet.where() == Where.ANYWHERE) { 108 return originalFacet; 109 } 110 // ensure that the contributed association is always disabled 111 return new DisabledFacetImpl(When.ALWAYS, Where.ANYWHERE, "Contributed collection", this); 112 } 113 114 @Override 115 public ObjectAdapter get(final ObjectAdapter ownerAdapter) { 116 return serviceAction.execute(serviceAdapter, new ObjectAdapter[]{ownerAdapter}); 117 } 118 119 @Override 120 public Identifier getIdentifier() { 121 return identifier; 122 } 123 124 @Override 125 public Consent isVisible(final AuthenticationSession session, final ObjectAdapter contributee, Where where) { 126 final VisibilityContext<?> ic = serviceAction.createVisibleInteractionContext(session, InteractionInvocationMethod.BY_USER, serviceAdapter, where); 127 ic.putContributee(0, contributee); // by definition, the contributee will be the first arg of the service action 128 return InteractionUtils.isVisibleResult(this, ic).createConsent(); 129 } 130 131 @Override 132 public Consent isUsable(final AuthenticationSession session, final ObjectAdapter contributee, Where where) { 133 final UsabilityContext<?> ic = serviceAction.createUsableInteractionContext(session, InteractionInvocationMethod.BY_USER, serviceAdapter, where); 134 ic.putContributee(0, contributee); // by definition, the contributee will be the first arg of the service action 135 return InteractionUtils.isUsableResult(this, ic).createConsent(); 136 } 137 138 139 // ////////////////////////////////////// 140 // FacetHolder 141 // ////////////////////////////////////// 142 143 @Override 144 public Class<? extends Facet>[] getFacetTypes() { 145 return facetHolder.getFacetTypes(); 146 } 147 148 @Override 149 public <T extends Facet> T getFacet(Class<T> cls) { 150 return facetHolder.getFacet(cls); 151 } 152 153 @Override 154 public boolean containsFacet(Class<? extends Facet> facetType) { 155 return facetHolder.containsFacet(facetType); 156 } 157 158 @Override 159 public boolean containsDoOpFacet(java.lang.Class<? extends Facet> facetType) { 160 return facetHolder.containsDoOpFacet(facetType); 161 } 162 163 @Override 164 public List<Facet> getFacets(Filter<Facet> filter) { 165 return facetHolder.getFacets(filter); 166 } 167 168 @Override 169 public void addFacet(Facet facet) { 170 facetHolder.addFacet(facet); 171 } 172 173 @Override 174 public void addFacet(MultiTypedFacet facet) { 175 facetHolder.addFacet(facet); 176 } 177 178 @Override 179 public void removeFacet(Facet facet) { 180 facetHolder.removeFacet(facet); 181 } 182 183 @Override 184 public void removeFacet(Class<? extends Facet> facetType) { 185 facetHolder.removeFacet(facetType); 186 } 187 188}