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.metamodel.facetapi;
021
022import static org.apache.isis.core.commons.ensure.Ensure.ensureThatArg;
023import static org.hamcrest.CoreMatchers.is;
024import static org.hamcrest.CoreMatchers.not;
025import static org.hamcrest.CoreMatchers.nullValue;
026
027import org.apache.isis.core.commons.ensure.Ensure;
028import org.apache.isis.core.commons.matchers.IsisMatchers;
029
030public abstract class FacetAbstract implements Facet {
031
032    public enum Derivation {
033        DERIVED,
034        NOT_DERIVED
035    }
036    
037    private Facet underlyingFacet;
038
039    private final Class<? extends Facet> facetType;
040    private final boolean derived;
041    private FacetHolder holder;
042
043    /**
044     * Populated in {@link #setFacetHolder(FacetHolder)} if the provided holder
045     * implements {@link IdentifiedHolder}.
046     * 
047     * <p>
048     * Otherwise is <tt>null</tt>.
049     */
050    private IdentifiedHolder identifiedHolder;
051
052    @SuppressWarnings("unchecked")
053    public FacetAbstract(final Class<? extends Facet> facetType, final FacetHolder holder, final Derivation derivation) {
054        this.facetType = ensureThatArg(facetType, is(not(nullValue(Class.class))));
055        setFacetHolder(ensureThatArg(holder, is(not(nullValue(FacetHolder.class)))));
056        this.derived = derivation == Derivation.DERIVED;
057    }
058
059    @Override
060    public final Class<? extends Facet> facetType() {
061        return facetType;
062    }
063
064    @Override
065    public FacetHolder getFacetHolder() {
066        return holder;
067    }
068
069    @Override
070    public boolean isDerived() {
071        return derived;
072    }
073
074    /**
075     * Convenience method that returns {@link #getFacetHolder()} downcast to
076     * {@link IdentifiedHolder} if the implementation does indeed inherit from
077     * {@link IdentifiedHolder}, otherwise <tt>null</tt>.
078     */
079    public IdentifiedHolder getIdentified() {
080        return identifiedHolder;
081    }
082
083    @Override
084    public Facet getUnderlyingFacet() {
085        return underlyingFacet;
086    }
087
088    @Override
089    public void setUnderlyingFacet(final Facet underlyingFacet) {
090        if(underlyingFacet != null) {
091            Ensure.ensureThatArg(underlyingFacet.facetType(), IsisMatchers.classEqualTo(facetType));
092        }
093        this.underlyingFacet = underlyingFacet;
094    }
095
096    /**
097     * Assume implementation is <i>not</i> a no-op.
098     * 
099     * <p>
100     * No-op implementations should override and return <tt>true</tt>.
101     */
102    @Override
103    public boolean isNoop() {
104        return false;
105    }
106
107    /**
108     * Default implementation of this method that returns <tt>true</tt>, ie
109     * should replace (none {@link #isNoop() no-op} implementations.
110     * 
111     * <p>
112     * Implementations that don't wish to replace none no-op implementations
113     * should override and return <tt>false</tt>.
114     */
115    @Override
116    public boolean alwaysReplace() {
117        return true;
118    }
119
120    @Override
121    public void setFacetHolder(final FacetHolder facetHolder) {
122        this.holder = facetHolder;
123        this.identifiedHolder = holder instanceof IdentifiedHolder ? (IdentifiedHolder) holder : null;
124    }
125
126    protected String toStringValues() {
127        return "";
128    }
129
130    @Override
131    public String toString() {
132        String details = "";
133        if (Validating.class.isAssignableFrom(getClass())) {
134            details += "Validating";
135        }
136        if (Disabling.class.isAssignableFrom(getClass())) {
137            details += (details.length() > 0 ? ";" : "") + "Disabling";
138        }
139        if (Hiding.class.isAssignableFrom(getClass())) {
140            details += (details.length() > 0 ? ";" : "") + "Hiding";
141        }
142        if (!"".equals(details)) {
143            details = "interaction=" + details + ",";
144        }
145
146        final String className = getClass().getName();
147        final String stringValues = toStringValues();
148        if (getClass() != facetType()) {
149            final String facetType = facetType().getName();
150            details += "type=" + facetType.substring(facetType.lastIndexOf('.') + 1);
151        }
152        if (!"".equals(stringValues)) {
153            details += ",";
154        }
155        return className.substring(className.lastIndexOf('.') + 1) + "[" + details + stringValues + "]";
156    }
157
158    /**
159     * Marker interface used within {@link #toString()}.
160     */
161    public static interface Hiding {
162    }
163
164    /**
165     * Marker interface used within {@link #toString()}.
166     */
167    public static interface Disabling {
168    }
169
170    /**
171     * Marker interface used within {@link #toString()}.
172     */
173    public static interface Validating {
174    }
175
176}