/*
* 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.facetapi;
import org.apache.isis.core.commons.ensure.Ensure;
import org.apache.isis.core.commons.matchers.IsisMatchers;
import static org.apache.isis.core.commons.ensure.Ensure.ensureThatArg;
import static org.hamcrest.CoreMatchers.*;
public abstract class FacetAbstract implements Facet {
public enum Derivation {
DERIVED,
NOT_DERIVED
}
private Facet underlyingFacet;
private final Class<? extends Facet> facetType;
private final boolean derived;
private FacetHolder holder;
/**
* Populated in {@link #setFacetHolder(FacetHolder)} if the provided holder
* implements {@link IdentifiedHolder}.
*
* <p>
* Otherwise is <tt>null</tt>.
*/
private IdentifiedHolder identifiedHolder;
@SuppressWarnings("unchecked")
public FacetAbstract(
final Class<? extends Facet> facetType,
final FacetHolder holder,
final Derivation derivation) {
this.facetType = ensureThatArg(facetType, is(not(nullValue(Class.class))));
setFacetHolder(ensureThatArg(holder, is(not(nullValue(FacetHolder.class)))));
this.derived = (derivation == Derivation.DERIVED);
}
@Override
public final Class<? extends Facet> facetType() {
return facetType;
}
@Override
public FacetHolder getFacetHolder() {
return holder;
}
@Override
public boolean isDerived() {
return derived;
}
/**
* Convenience method that returns {@link #getFacetHolder()} downcast to
* {@link IdentifiedHolder} if the implementation does indeed inherit from
* {@link IdentifiedHolder}, otherwise <tt>null</tt>.
*/
public IdentifiedHolder getIdentified() {
return identifiedHolder;
}
@Override
public Facet getUnderlyingFacet() {
return underlyingFacet;
}
@Override
public void setUnderlyingFacet(final Facet underlyingFacet) {
if(underlyingFacet != null) {
if(underlyingFacet instanceof MultiTypedFacet) {
final MultiTypedFacet multiTypedFacet = (MultiTypedFacet) underlyingFacet;
final boolean matches = compatible(multiTypedFacet);
if(!matches) {
throw new IllegalArgumentException("illegal argument, expected underlying facet (a multi-valued facet) to have equivalent to the facet type (or facet types) of this facet");
}
} else {
Ensure.ensureThatArg(underlyingFacet.facetType(), IsisMatchers.classEqualTo(facetType));
}
}
this.underlyingFacet = underlyingFacet;
}
private boolean compatible(final MultiTypedFacet multiTypedFacet) {
if (!(this instanceof MultiTypedFacet)) {
return multiTypedFacet.containsFacetTypeOf(this.facetType);
}
final MultiTypedFacet thisAsMultiTyped = (MultiTypedFacet) this;
final Class<? extends Facet>[] facetTypes = thisAsMultiTyped.facetTypes();
for (final Class<? extends Facet> facetType : facetTypes) {
if(multiTypedFacet.containsFacetTypeOf(facetType)) {
return true;
}
}
return false;
}
/**
* Assume implementation is <i>not</i> a no-op.
*
* <p>
* No-op implementations should override and return <tt>true</tt>.
*/
@Override
public boolean isNoop() {
return false;
}
/**
* Default implementation of this method that returns <tt>true</tt>, ie
* should replace (none {@link #isNoop() no-op} implementations.
*
* <p>
* Implementations that don't wish to replace none no-op implementations
* should override and return <tt>false</tt>.
*/
@Override
public boolean alwaysReplace() {
return true;
}
@Override
public void setFacetHolder(final FacetHolder facetHolder) {
this.holder = facetHolder;
this.identifiedHolder = holder instanceof IdentifiedHolder ? (IdentifiedHolder) holder : null;
}
protected String toStringValues() {
return "";
}
@Override
public String toString() {
String details = "";
if (Validating.class.isAssignableFrom(getClass())) {
details += "Validating";
}
if (Disabling.class.isAssignableFrom(getClass())) {
details += (details.length() > 0 ? ";" : "") + "Disabling";
}
if (Hiding.class.isAssignableFrom(getClass())) {
details += (details.length() > 0 ? ";" : "") + "Hiding";
}
if (!"".equals(details)) {
details = "interaction=" + details + ",";
}
final String className = getClass().getName();
final String stringValues = toStringValues();
if (getClass() != facetType()) {
final String facetType = facetType().getName();
details += "type=" + facetType.substring(facetType.lastIndexOf('.') + 1);
}
if (!"".equals(stringValues)) {
details += ",";
}
return className.substring(className.lastIndexOf('.') + 1) + "[" + details + stringValues + "]";
}
/**
* Marker interface used within {@link #toString()}.
*/
public static interface Hiding {
}
/**
* Marker interface used within {@link #toString()}.
*/
public static interface Disabling {
}
/**
* Marker interface used within {@link #toString()}.
*/
public static interface Validating {
}
}