/*
* 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();
}
}