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}