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.progmodel.facets.object.value;
021
022import org.apache.isis.applib.adapters.DefaultsProvider;
023import org.apache.isis.applib.adapters.EncoderDecoder;
024import org.apache.isis.applib.adapters.Parser;
025import org.apache.isis.applib.adapters.ValueSemanticsProvider;
026import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
027import org.apache.isis.core.commons.config.IsisConfiguration;
028import org.apache.isis.core.commons.lang.ClassExtensions;
029import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
030import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
031import org.apache.isis.core.metamodel.facetapi.Facet;
032import org.apache.isis.core.metamodel.facetapi.FacetHolder;
033import org.apache.isis.core.metamodel.facetapi.FacetHolderImpl;
034import org.apache.isis.core.metamodel.facets.MultipleValueFacetAbstract;
035import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
036import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
037import org.apache.isis.core.progmodel.facets.object.defaults.DefaultedFacetUsingDefaultsProvider;
038import org.apache.isis.core.progmodel.facets.object.encodeable.EncodableFacetUsingEncoderDecoder;
039import org.apache.isis.core.progmodel.facets.object.parseable.ParseableFacetUsingParser;
040import org.apache.isis.core.progmodel.facets.object.title.TitleFacetUsingParser;
041
042public abstract class ValueFacetAbstract extends MultipleValueFacetAbstract implements ValueFacet {
043
044    public static Class<? extends Facet> type() {
045        return ValueFacet.class;
046    }
047
048    private static ValueSemanticsProvider<?> newValueSemanticsProviderOrNull(final Class<?> semanticsProviderClass, final FacetHolder holder, final IsisConfiguration configuration, final ValueSemanticsProviderContext context) {
049        if (semanticsProviderClass == null) {
050            return null;
051        }
052        return (ValueSemanticsProvider<?>) ClassExtensions.newInstance(semanticsProviderClass, new Class<?>[] { FacetHolder.class, IsisConfiguration.class, ValueSemanticsProviderContext.class }, new Object[] { holder, configuration, context });
053    }
054
055    // to look after the facets (since MultiTyped)
056    private final FacetHolder facetHolder = new FacetHolderImpl();
057
058    private final ValueSemanticsProvider<?> semanticsProvider;
059
060    private final ValueSemanticsProviderContext context;
061
062    public enum AddFacetsIfInvalidStrategy {
063        DO_ADD(true), DONT_ADD(false);
064        private boolean addFacetsIfInvalid;
065
066        private AddFacetsIfInvalidStrategy(final boolean addFacetsIfInvalid) {
067            this.addFacetsIfInvalid = addFacetsIfInvalid;
068        }
069
070        public boolean shouldAddFacetsIfInvalid() {
071            return addFacetsIfInvalid;
072        }
073    }
074
075    public ValueFacetAbstract(final Class<?> semanticsProviderClass, final AddFacetsIfInvalidStrategy addFacetsIfInvalid, final FacetHolder holder, final IsisConfiguration configuration, final ValueSemanticsProviderContext context) {
076        this(newValueSemanticsProviderOrNull(semanticsProviderClass, holder, configuration, context), addFacetsIfInvalid, holder, context);
077    }
078
079    public ValueFacetAbstract(final ValueSemanticsProvider<?> semanticsProvider, final AddFacetsIfInvalidStrategy addFacetsIfInvalid, final FacetHolder holder, final ValueSemanticsProviderContext context) {
080        super(type(), holder);
081
082        this.semanticsProvider = semanticsProvider;
083        this.context = context;
084
085        // note: we can't use the runtimeContext to inject dependencies into the
086        // semanticsProvider,
087        // because there won't be any PersistenceSession when initially building
088        // the metamodel.
089        // so, we defer until we use the parser.
090
091        if (!isValid() && !addFacetsIfInvalid.shouldAddFacetsIfInvalid()) {
092            return;
093        }
094
095        // we now figure add all the facets supported. Note that we do not use
096        // FacetUtil.addFacet,
097        // because we need to add them explicitly to our delegate facetholder
098        // but have the
099        // facets themselves reference this value's holder.
100
101        facetHolder.addFacet((Facet) this); // add just ValueFacet.class
102                                            // initially.
103
104        // we used to add aggregated here, but this was wrong.
105        // An immutable value is not aggregated, it is shared.
106
107        // ImmutableFacet, if appropriate
108        final boolean immutable = semanticsProvider != null ? semanticsProvider.isImmutable() : true;
109        if (immutable) {
110            facetHolder.addFacet(new ImmutableFacetViaValueSemantics(holder));
111        }
112
113        // EqualByContentFacet, if appropriate
114        final boolean equalByContent = semanticsProvider != null ? semanticsProvider.isEqualByContent() : true;
115        if (equalByContent) {
116            facetHolder.addFacet(new EqualByContentFacetViaValueSemantics(holder));
117        }
118
119        if (semanticsProvider != null) {
120
121            // install the EncodeableFacet if we've been given an EncoderDecoder
122            final EncoderDecoder<?> encoderDecoder = semanticsProvider.getEncoderDecoder();
123            if (encoderDecoder != null) {
124                facetHolder.addFacet(new EncodableFacetUsingEncoderDecoder(encoderDecoder, holder, getAdapterMap(), getDependencyInjector()));
125            }
126
127            // install the ParseableFacet and other facets if we've been given a
128            // Parser
129            final Parser<?> parser = semanticsProvider.getParser();
130            if (parser != null) {
131                facetHolder.addFacet(new ParseableFacetUsingParser(parser, holder, getDeploymentCategory(context), getAuthenticationSessionProvider(), getDependencyInjector(), getAdapterMap()));
132                facetHolder.addFacet(new TitleFacetUsingParser(parser, holder, getDependencyInjector()));
133                facetHolder.addFacet(new TypicalLengthFacetUsingParser(parser, holder, getDependencyInjector()));
134            }
135
136            // install the DefaultedFacet if we've been given a DefaultsProvider
137            final DefaultsProvider<?> defaultsProvider = semanticsProvider.getDefaultsProvider();
138            if (defaultsProvider != null) {
139                facetHolder.addFacet(new DefaultedFacetUsingDefaultsProvider(defaultsProvider, holder, getDependencyInjector()));
140            }
141        }
142    }
143
144    public boolean isValid() {
145        return this.semanticsProvider != null;
146    }
147
148    // /////////////////////////////
149    // MultiTypedFacet impl
150    // /////////////////////////////
151    @Override
152    public Class<? extends Facet>[] facetTypes() {
153        return facetHolder.getFacetTypes();
154    }
155
156    @Override
157    public <T extends Facet> T getFacet(final Class<T> facetType) {
158        return facetHolder.getFacet(facetType);
159    }
160
161    // /////////////////////////////////////////
162    // Dependencies (from constructor)
163    // /////////////////////////////////////////
164
165    protected DeploymentCategory getDeploymentCategory(final ValueSemanticsProviderContext context) {
166        return context.getDeploymentCategory();
167    }
168
169    public AdapterManager getAdapterMap() {
170        return context.getAdapterManager();
171    }
172
173    public ServicesInjector getDependencyInjector() {
174        return context.getDependencyInjector();
175    }
176
177    public AuthenticationSessionProvider getAuthenticationSessionProvider() {
178        return context.getAuthenticationSessionProvider();
179    }
180
181}