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 }