001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *        http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 */
019
020package org.apache.isis.core.metamodel.specloader.specimpl;
021
022import java.util.List;
023
024import org.apache.isis.applib.Identifier;
025import org.apache.isis.applib.annotation.When;
026import org.apache.isis.applib.annotation.Where;
027import org.apache.isis.applib.filter.Filter;
028import org.apache.isis.core.commons.authentication.AuthenticationSession;
029import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
030import org.apache.isis.core.commons.lang.StringExtensions;
031import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
032import org.apache.isis.core.metamodel.adapter.QuerySubmitter;
033import org.apache.isis.core.metamodel.adapter.ServicesProvider;
034import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
035import org.apache.isis.core.metamodel.consent.Consent;
036import org.apache.isis.core.metamodel.consent.InteractionInvocationMethod;
037import org.apache.isis.core.metamodel.consent.InteractionResult;
038import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
039import org.apache.isis.core.metamodel.facetapi.Facet;
040import org.apache.isis.core.metamodel.facetapi.FeatureType;
041import org.apache.isis.core.metamodel.facetapi.MultiTypedFacet;
042import org.apache.isis.core.metamodel.facets.FacetedMethod;
043import org.apache.isis.core.metamodel.facets.describedas.DescribedAsFacet;
044import org.apache.isis.core.metamodel.facets.help.HelpFacet;
045import org.apache.isis.core.metamodel.facets.hide.HiddenFacet;
046import org.apache.isis.core.metamodel.facets.named.NamedFacet;
047import org.apache.isis.core.metamodel.interactions.DisablingInteractionAdvisor;
048import org.apache.isis.core.metamodel.interactions.HidingInteractionAdvisor;
049import org.apache.isis.core.metamodel.interactions.InteractionUtils;
050import org.apache.isis.core.metamodel.interactions.UsabilityContext;
051import org.apache.isis.core.metamodel.interactions.VisibilityContext;
052import org.apache.isis.core.metamodel.spec.ObjectSpecification;
053import org.apache.isis.core.metamodel.spec.SpecificationLoader;
054import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
055import org.apache.isis.core.metamodel.spec.feature.ObjectMemberContext;
056import org.apache.isis.core.metamodel.specloader.collectiontyperegistry.CollectionTypeRegistry;
057
058public abstract class ObjectMemberAbstract implements ObjectMember {
059
060    public static ObjectSpecification getSpecification(final SpecificationLoader specificationLookup, final Class<?> type) {
061        return type == null ? null : specificationLookup.loadSpecification(type);
062    }
063
064    protected final String defaultName;
065    private final String id;
066    private final FacetedMethod facetedMethod;
067    private final FeatureType featureType;
068    private final AuthenticationSessionProvider authenticationSessionProvider;
069    private final SpecificationLoader specificationLookup;
070    private final AdapterManager adapterManager;
071    private final ServicesProvider servicesProvider;
072    private final QuerySubmitter querySubmitter;
073    private final CollectionTypeRegistry collectionTypeRegistry;
074    private final DeploymentCategory deploymentCategory;
075
076    protected ObjectMemberAbstract(final FacetedMethod facetedMethod, final FeatureType featureType, final ObjectMemberContext objectMemberContext) {
077        final String id = facetedMethod.getIdentifier().getMemberName();
078        if (id == null) {
079            throw new IllegalArgumentException("Name must always be set");
080        }
081        this.facetedMethod = facetedMethod;
082        this.featureType = featureType;
083        this.id = id;
084        this.defaultName = StringExtensions.asNaturalName2(this.id);
085
086        this.deploymentCategory = objectMemberContext.getDeploymentCategory();
087        this.authenticationSessionProvider = objectMemberContext.getAuthenticationSessionProvider();
088        this.specificationLookup = objectMemberContext.getSpecificationLookup();
089        this.adapterManager = objectMemberContext.getAdapterManager();
090        this.servicesProvider = objectMemberContext.getServicesProvider();
091        this.querySubmitter = objectMemberContext.getQuerySubmitter();
092        this.collectionTypeRegistry = objectMemberContext.getCollectionTypeRegistry();
093    }
094
095    // /////////////////////////////////////////////////////////////
096    // from context
097    // /////////////////////////////////////////////////////////////
098
099    public DeploymentCategory getDeploymentCategory() {
100        return deploymentCategory;
101    }
102    
103    // /////////////////////////////////////////////////////////////
104    // Identifiers
105    // /////////////////////////////////////////////////////////////
106
107    @Override
108    public String getId() {
109        return id;
110    }
111
112    /**
113     * @return the facetedMethod
114     */
115    public FacetedMethod getFacetedMethod() {
116        return facetedMethod;
117    }
118
119    @Override
120    public Identifier getIdentifier() {
121        return getFacetedMethod().getIdentifier();
122    }
123
124    @Override
125    public FeatureType getFeatureType() {
126        return featureType;
127    }
128
129    // /////////////////////////////////////////////////////////////
130    // Facets
131    // /////////////////////////////////////////////////////////////
132
133    @Override
134    public boolean containsFacet(final Class<? extends Facet> facetType) {
135        return getFacetedMethod().containsFacet(facetType);
136    }
137
138    @Override
139    public boolean containsDoOpFacet(final Class<? extends Facet> facetType) {
140        return getFacetedMethod().containsDoOpFacet(facetType);
141    }
142
143    @Override
144    public <T extends Facet> T getFacet(final Class<T> cls) {
145        return getFacetedMethod().getFacet(cls);
146    }
147
148    @Override
149    public Class<? extends Facet>[] getFacetTypes() {
150        return getFacetedMethod().getFacetTypes();
151    }
152
153    @Override
154    public List<Facet> getFacets(final Filter<Facet> filter) {
155        return getFacetedMethod().getFacets(filter);
156    }
157
158    @Override
159    public void addFacet(final Facet facet) {
160        getFacetedMethod().addFacet(facet);
161    }
162
163    @Override
164    public void addFacet(final MultiTypedFacet facet) {
165        getFacetedMethod().addFacet(facet);
166    }
167
168    @Override
169    public void removeFacet(final Facet facet) {
170        getFacetedMethod().removeFacet(facet);
171    }
172
173    @Override
174    public void removeFacet(final Class<? extends Facet> facetType) {
175        getFacetedMethod().removeFacet(facetType);
176    }
177
178    // /////////////////////////////////////////////////////////////
179    // Name, Description, Help (convenience for facets)
180    // /////////////////////////////////////////////////////////////
181
182    /**
183     * Return the default label for this member. This is based on the name of
184     * this member.
185     * 
186     * @see #getId()
187     */
188    @Override
189    public String getName() {
190        final NamedFacet facet = getFacet(NamedFacet.class);
191        final String name = facet.value();
192        return name != null ? name : defaultName;
193    }
194
195    @Override
196    public String getDescription() {
197        final DescribedAsFacet facet = getFacet(DescribedAsFacet.class);
198        return facet.value();
199    }
200
201    @Override
202    public String getHelp() {
203        final HelpFacet facet = getFacet(HelpFacet.class);
204        return facet.value();
205    }
206
207    // /////////////////////////////////////////////////////////////
208    // Hidden (or visible)
209    // /////////////////////////////////////////////////////////////
210
211    @Override
212    public boolean isAlwaysHidden() {
213        final HiddenFacet hiddenFacet = getFacet(HiddenFacet.class);
214        return hiddenFacet != null && hiddenFacet.when() == When.ALWAYS && hiddenFacet.where() == Where.ANYWHERE;
215    }
216
217    /**
218     * Loops over all {@link HidingInteractionAdvisor} {@link Facet}s and
219     * returns <tt>true</tt> only if none hide the member.
220     * 
221     * <p>
222     * TODO: currently this method is hard-coded to assume all interactions are
223     * initiated {@link InteractionInvocationMethod#BY_USER by user}.
224     */
225    @Override
226    public Consent isVisible(final AuthenticationSession session, final ObjectAdapter target, Where where) {
227        return isVisibleResult(deploymentCategory, session, target, where).createConsent();
228    }
229
230    private InteractionResult isVisibleResult(DeploymentCategory deploymentCategory, final AuthenticationSession session, final ObjectAdapter target, Where where) {
231        final VisibilityContext<?> ic = createVisibleInteractionContext(session, InteractionInvocationMethod.BY_USER, target, where);
232        return InteractionUtils.isVisibleResult(this, ic);
233    }
234
235    // /////////////////////////////////////////////////////////////
236    // Disabled (or enabled)
237    // /////////////////////////////////////////////////////////////
238
239    /**
240     * Loops over all {@link DisablingInteractionAdvisor} {@link Facet}s and
241     * returns <tt>true</tt> only if none disables the member.
242     * 
243     * <p>
244     * TODO: currently this method is hard-coded to assume all interactions are
245     * initiated {@link InteractionInvocationMethod#BY_USER by user}.
246     */
247    @Override
248    public Consent isUsable(final AuthenticationSession session, final ObjectAdapter target, Where where) {
249        return isUsableResult(session, target, where).createConsent();
250    }
251
252    private InteractionResult isUsableResult(final AuthenticationSession session, final ObjectAdapter target, Where where) {
253        final UsabilityContext<?> ic = createUsableInteractionContext(session, InteractionInvocationMethod.BY_USER, target, where);
254        return InteractionUtils.isUsableResult(this, ic);
255    }
256
257    // //////////////////////////////////////////////////////////////////
258    // isAssociation, isAction
259    // //////////////////////////////////////////////////////////////////
260
261    @Override
262    public boolean isAction() {
263        return featureType.isAction();
264    }
265
266    @Override
267    public boolean isPropertyOrCollection() {
268        return featureType.isPropertyOrCollection();
269    }
270
271    @Override
272    public boolean isOneToManyAssociation() {
273        return featureType.isCollection();
274    }
275
276    @Override
277    public boolean isOneToOneAssociation() {
278        return featureType.isProperty();
279    }
280
281    // //////////////////////////////////////////////////////////////////
282    // Convenience
283    // //////////////////////////////////////////////////////////////////
284
285    /**
286     * The current {@link AuthenticationSession} (can change over time so do not
287     * cache).
288     */
289    protected AuthenticationSession getAuthenticationSession() {
290        return authenticationSessionProvider.getAuthenticationSession();
291    }
292
293    // //////////////////////////////////////////////////////////////////
294    // toString
295    // //////////////////////////////////////////////////////////////////
296
297    @Override
298    public String toString() {
299        return String.format("id=%s,name='%s'", getId(), getName());
300    }
301
302    // //////////////////////////////////////////////////////////////////
303    // Dependencies
304    // //////////////////////////////////////////////////////////////////
305
306    public AuthenticationSessionProvider getAuthenticationSessionProvider() {
307        return authenticationSessionProvider;
308    }
309
310    public SpecificationLoader getSpecificationLookup() {
311        return specificationLookup;
312    }
313
314    public AdapterManager getAdapterManager() {
315        return adapterManager;
316    }
317
318    public ServicesProvider getServicesProvider() {
319        return servicesProvider;
320    }
321
322    public QuerySubmitter getQuerySubmitter() {
323        return querySubmitter;
324    }
325
326    public CollectionTypeRegistry getCollectionTypeRegistry() {
327        return collectionTypeRegistry;
328    }
329}