/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.isis.core.metamodel.facets.object.value; import org.apache.isis.applib.adapters.*; import org.apache.isis.core.commons.lang.ClassExtensions; import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager; import org.apache.isis.core.metamodel.deployment.DeploymentCategory; import org.apache.isis.core.metamodel.facetapi.Facet; import org.apache.isis.core.metamodel.facetapi.FacetHolder; import org.apache.isis.core.metamodel.facetapi.FacetHolderImpl; import org.apache.isis.core.metamodel.facets.MultipleValueFacetAbstract; import org.apache.isis.core.metamodel.facets.object.defaults.DefaultedFacetUsingDefaultsProvider; import org.apache.isis.core.metamodel.facets.object.encodeable.encoder.EncodableFacetUsingEncoderDecoder; import org.apache.isis.core.metamodel.facets.object.parseable.parser.ParseableFacetUsingParser; import org.apache.isis.core.metamodel.facets.object.title.parser.TitleFacetUsingParser; import org.apache.isis.core.metamodel.services.ServicesInjector; public abstract class ValueFacetAbstract extends MultipleValueFacetAbstract implements ValueFacet { public static Class<? extends Facet> type() { return ValueFacet.class; } private static ValueSemanticsProvider<?> newValueSemanticsProviderOrNull(final Class<?> semanticsProviderClass, final FacetHolder holder, final ServicesInjector servicesInjector) { if (semanticsProviderClass == null) { return null; } return (ValueSemanticsProvider<?>) ClassExtensions.newInstance(semanticsProviderClass, new Class<?>[] { FacetHolder.class, ServicesInjector.class }, new Object[] { holder, servicesInjector }); } // to look after the facets (since MultiTyped) private final FacetHolder facetHolder = new FacetHolderImpl(); private final ValueSemanticsProvider<?> semanticsProvider; private final ServicesInjector servicesInjector; public enum AddFacetsIfInvalidStrategy { DO_ADD(true), DONT_ADD(false); private boolean addFacetsIfInvalid; private AddFacetsIfInvalidStrategy(final boolean addFacetsIfInvalid) { this.addFacetsIfInvalid = addFacetsIfInvalid; } public boolean shouldAddFacetsIfInvalid() { return addFacetsIfInvalid; } } public ValueFacetAbstract(final Class<?> semanticsProviderClass, final AddFacetsIfInvalidStrategy addFacetsIfInvalid, final FacetHolder holder, final ServicesInjector servicesInjector) { this(newValueSemanticsProviderOrNull(semanticsProviderClass, holder, servicesInjector), addFacetsIfInvalid, holder, servicesInjector); } public ValueFacetAbstract(final ValueSemanticsProvider<?> semanticsProvider, final AddFacetsIfInvalidStrategy addFacetsIfInvalid, final FacetHolder holder, final ServicesInjector servicesInjector) { super(type(), holder); this.semanticsProvider = semanticsProvider; this.servicesInjector = servicesInjector; // note: we can't use the runtimeContext to inject dependencies into the // semanticsProvider, // because there won't be any PersistenceSession when initially building // the metamodel. // so, we defer until we use the parser. if (!isValid() && !addFacetsIfInvalid.shouldAddFacetsIfInvalid()) { return; } // we now figure add all the facets supported. Note that we do not use // FacetUtil.addFacet, // because we need to add them explicitly to our delegate facetholder // but have the // facets themselves reference this value's holder. facetHolder.addFacet((Facet) this); // add just ValueFacet.class // initially. // we used to add aggregated here, but this was wrong. // An immutable value is not aggregated, it is shared. // ImmutableFacet, if appropriate final boolean immutable = semanticsProvider == null || semanticsProvider.isImmutable(); if (immutable) { facetHolder.addFacet(new ImmutableFacetViaValueSemantics(holder)); } // EqualByContentFacet, if appropriate final boolean equalByContent = semanticsProvider == null || semanticsProvider.isEqualByContent(); if (equalByContent) { facetHolder.addFacet(new EqualByContentFacetViaValueSemantics(holder)); } if (semanticsProvider != null) { // install the EncodeableFacet if we've been given an EncoderDecoder final EncoderDecoder<?> encoderDecoder = semanticsProvider.getEncoderDecoder(); if (encoderDecoder != null) { facetHolder.addFacet(new EncodableFacetUsingEncoderDecoder(encoderDecoder, holder, getAdapterMap(), this.servicesInjector)); } // install the ParseableFacet and other facets if we've been given a // Parser final Parser<?> parser = semanticsProvider.getParser(); if (parser != null) { facetHolder.addFacet(new ParseableFacetUsingParser(parser, holder, this.servicesInjector)); facetHolder.addFacet(new TitleFacetUsingParser(parser, holder, this.servicesInjector)); facetHolder.addFacet(new TypicalLengthFacetUsingParser(parser, holder, this.servicesInjector)); if(parser instanceof Parser2) { final Parser2 parser2 = (Parser2) parser; final Integer maxLength = parser2.maxLength(); if(maxLength != null) { facetHolder.addFacet(new MaxLengthFacetUsingParser2(parser2, holder, this.servicesInjector)); } } } // install the DefaultedFacet if we've been given a DefaultsProvider final DefaultsProvider<?> defaultsProvider = semanticsProvider.getDefaultsProvider(); if (defaultsProvider != null) { facetHolder.addFacet(new DefaultedFacetUsingDefaultsProvider(defaultsProvider, holder, this.servicesInjector)); } } } public boolean isValid() { return this.semanticsProvider != null; } // ///////////////////////////// // MultiTypedFacet impl // ///////////////////////////// @Override public Class<? extends Facet>[] facetTypes() { return facetHolder.getFacetTypes(); } @Override public <T extends Facet> T getFacet(final Class<T> facetType) { return facetHolder.getFacet(facetType); } @Override public boolean containsFacetTypeOf(final Class<? extends Facet> requiredFacetType) { for (final Class<? extends Facet> facetType : facetTypes()) { if(facetType == requiredFacetType) { return true; } } return false; } // ///////////////////////////////////////// // Dependencies (from constructor) // ///////////////////////////////////////// protected DeploymentCategory getDeploymentCategory(final ServicesInjector servicesInjector) { return servicesInjector.getDeploymentCategoryProvider().getDeploymentCategory(); } private AdapterManager getAdapterMap() { return servicesInjector.getPersistenceSessionServiceInternal(); } }