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