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.spec;
021
022import java.util.Collections;
023import java.util.Comparator;
024import java.util.List;
025
026import com.google.common.base.Function;
027
028import org.apache.isis.applib.annotation.ObjectType;
029import org.apache.isis.applib.filter.Filter;
030import org.apache.isis.applib.profiles.Localization;
031import org.apache.isis.core.commons.authentication.AuthenticationSession;
032import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
033import org.apache.isis.core.metamodel.consent.Consent;
034import org.apache.isis.core.metamodel.consent.InteractionInvocationMethod;
035import org.apache.isis.core.metamodel.consent.InteractionResult;
036import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
037import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
038import org.apache.isis.core.metamodel.facets.describedas.DescribedAsFacet;
039import org.apache.isis.core.metamodel.facets.help.HelpFacet;
040import org.apache.isis.core.metamodel.facets.hide.HiddenFacet;
041import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
042import org.apache.isis.core.metamodel.facets.named.NamedFacet;
043import org.apache.isis.core.metamodel.facets.object.aggregated.ParentedFacet;
044import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
045import org.apache.isis.core.metamodel.facets.object.icon.IconFacet;
046import org.apache.isis.core.metamodel.facets.object.immutable.ImmutableFacet;
047import org.apache.isis.core.metamodel.facets.object.objecttype.ObjectSpecIdFacet;
048import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
049import org.apache.isis.core.metamodel.facets.object.plural.PluralFacet;
050import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
051import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
052import org.apache.isis.core.metamodel.interactions.InteractionContext;
053import org.apache.isis.core.metamodel.interactions.ObjectTitleContext;
054import org.apache.isis.core.metamodel.interactions.ObjectValidityContext;
055import org.apache.isis.core.metamodel.spec.feature.ObjectActionContainer;
056import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
057import org.apache.isis.core.metamodel.spec.feature.ObjectAssociationContainer;
058import org.apache.isis.core.metamodel.specloader.classsubstitutor.ClassSubstitutor;
059
060/**
061 * Represents an entity or value (cf {@link java.lang.Class}) within the
062 * metamodel.
063 * 
064 * <p>
065 * As specifications are cyclic (specifically a class will reference its
066 * subclasses, which in turn reference their superclass) they need be created
067 * first, and then later work out its internals. Hence we create
068 * {@link ObjectSpecification}s as we need them, and then introspect them later.
069 */
070public interface ObjectSpecification extends Specification, ObjectActionContainer, ObjectAssociationContainer, Hierarchical, Dirtiable, DefaultProvider {
071
072    public final static List<ObjectSpecification> EMPTY_LIST = Collections.emptyList();
073
074    public final static Function<ObjectSpecification, String> FUNCTION_FULLY_QUALIFIED_CLASS_NAME = new Function<ObjectSpecification, String>() {
075        @Override
076        public String apply(final ObjectSpecification from) {
077            return from.getFullIdentifier();
078        }
079    };
080    public final static Comparator<ObjectSpecification> COMPARATOR_FULLY_QUALIFIED_CLASS_NAME = new Comparator<ObjectSpecification>() {
081        @Override
082        public int compare(final ObjectSpecification o1, final ObjectSpecification o2) {
083            return o1.getFullIdentifier().compareTo(o2.getFullIdentifier());
084        }
085    };
086    public final static Comparator<ObjectSpecification> COMPARATOR_SHORT_IDENTIFIER_IGNORE_CASE = new Comparator<ObjectSpecification>() {
087        @Override
088        public int compare(final ObjectSpecification s1, final ObjectSpecification s2) {
089            return s1.getShortIdentifier().compareToIgnoreCase(s2.getShortIdentifier());
090        }
091    };
092
093    /**
094     * @return
095     */
096    Class<?> getCorrespondingClass();
097
098    /**
099     * Returns the (unique) spec Id, as per the {@link ObjectSpecIdFacet}.
100     * 
101     * <p>
102     * This will typically be the value of the {@link ObjectType} annotation (or equivalent);
103     * if non has been specified then will default to the fully qualified class name (with
104     * {@link ClassSubstitutor class name substituted} if necessary to allow for runtime bytecode enhancement.
105     * 
106     * <p>
107     * The {@link ObjectSpecification} can be retrieved using {@link SpecificationLoader#lookupBySpecId(ObjectSpecId)}.
108     */
109    ObjectSpecId getSpecId();
110    
111    /**
112     * Returns an (immutable) "full" identifier for this specification.
113     * 
114     * <p>
115     * This will be the fully qualified name of the Class object that this
116     * object represents (i.e. it includes the package name).
117     */
118    String getFullIdentifier();
119    
120    /**
121     * Returns an (immutable) "short" identifier for this specification.
122     * 
123     * <p>
124     * This will be the class name without the package; any text up to and
125     * including the last period is removed.
126     */
127    String getShortIdentifier();
128
129    /**
130     * Returns the (singular) name for objects of this specification.
131     * 
132     * <p>
133     * Corresponds to the {@link NamedFacet#value()} of {@link NamedFacet}; is
134     * not necessarily immutable.
135     */
136    String getSingularName();
137
138    /**
139     * Returns the plural name for objects of this specification.
140     * 
141     * <p>
142     * Corresponds to the {@link PluralFacet#value() value} of
143     * {@link PluralFacet}; is not necessarily immutable.
144     */
145    String getPluralName();
146
147    /**
148     * Returns the description, if any, of the specification.
149     * 
150     * <p>
151     * Corresponds to the {@link DescribedAsFacet#value()) value} of
152     * {@link DescribedAsFacet}; is not necessarily immutable.
153     */
154    @Override
155    String getDescription();
156
157    /**
158     * Returns a help string or lookup reference, if any, of the specification.
159     * 
160     * <p>
161     * Corresponds to the {@link HelpFacet#value()) value} of {@link HelpFacet};
162     * is not necessarily immutable.
163     */
164    String getHelp();
165
166    /**
167     * Returns a css class name of the specification.
168     *
169     * <p>
170     * Corresponds to the {@link CssClass#value()) value} of {@link CssClassFacet};
171     */
172    String getCssClass();
173
174    /**
175     * Returns the title string for the specified object.
176     * 
177     * <p>
178     * Corresponds to the {@link TitleFacet#value()) value} of
179     * {@link TitleFacet}; is not necessarily immutable.
180     * 
181     * @deprecated use {@link #getTitle(ObjectAdapter, ObjectAdapter, Localization)}
182     */
183    @Deprecated
184    String getTitle(ObjectAdapter adapter, Localization localization);
185
186    /**
187     * Returns the title to display of target adapter, rendered within the context
188     * of some other adapter (if any).
189     * 
190     * <p>
191     * @see TitleFacet#title(ObjectAdapter, ObjectAdapter, org.apache.isis.applib.profiles.Localization)
192     */
193    String getTitle(ObjectAdapter contextAdapterIfAny, ObjectAdapter targetAdapter, Localization localization);
194
195    /**
196     * Returns the name of an icon to use for the specified object.
197     * 
198     * <p>
199     * Corresponds to the {@link IconFacet#iconName(ObjectAdapter)) icon name}
200     * returned by the {@link IconFacet}; is not necessarily immutable.
201     */
202    String getIconName(ObjectAdapter object);
203
204    boolean isAbstract();
205
206    // //////////////////////////////////////////////////////////////
207    // TitleContext
208    // //////////////////////////////////////////////////////////////
209
210    /**
211     * Create an {@link InteractionContext} representing an attempt to read the
212     * object's title.
213     */
214    ObjectTitleContext createTitleInteractionContext(AuthenticationSession session, InteractionInvocationMethod invocationMethod, ObjectAdapter targetObjectAdapter);
215
216    // //////////////////////////////////////////////////////////////
217    // ValidityContext, Validity
218    // //////////////////////////////////////////////////////////////
219
220    /**
221     * Create an {@link InteractionContext} representing an attempt to save the
222     * object.
223     * @param deploymentCategory TODO
224     */
225    ObjectValidityContext createValidityInteractionContext(DeploymentCategory deploymentCategory, AuthenticationSession session, InteractionInvocationMethod invocationMethod, ObjectAdapter targetObjectAdapter);
226
227    /**
228     * Determines whether the specified object is in a valid state (for example,
229     * so can be persisted); represented as a {@link Consent}.
230     */
231    Consent isValid(ObjectAdapter adapter);
232
233    /**
234     * Determines whether the specified object is in a valid state (for example,
235     * so can be persisted); represented as a {@link InteractionResult}.
236     */
237    InteractionResult isValidResult(ObjectAdapter adapter);
238
239    // //////////////////////////////////////////////////////////////
240    // Facets
241    // //////////////////////////////////////////////////////////////
242
243    /**
244     * Determines if objects of this specification can be persisted or not. If
245     * it can be persisted (i.e. it return something other than
246     * {@link Persistability}.TRANSIENT ObjectAdapter.isPersistent() will
247     * indicated whether the object is persistent or not. If they cannot be
248     * persisted then {@link ObjectAdapter}. {@link #persistability()} should be
249     * ignored.
250     */
251    Persistability persistability();
252
253    /**
254     * Determines if the object represents an value or object.
255     * 
256     * <p>
257     * In effect, means that it doesn't have the {@link CollectionFacet}, and
258     * therefore will return NOT {@link #isParentedOrFreeCollection()}
259     * 
260     * @see #isCollection().
261     */
262    boolean isNotCollection();
263
264    /**
265     * Determines if objects of this type are a parented (internal) or free-standing (external) collection.
266     * 
267     * <p>
268     * In effect, means has got {@link CollectionFacet}, and therefore will
269     * return NOT {@link #isNotCollection()}.
270     * 
271     * @see #isNotCollection()
272     */
273    boolean isParentedOrFreeCollection();
274
275    /**
276     * Determines if objects of this type are values.
277     * 
278     * <p>
279     * In effect, means has got {@link ValueFacet}.
280     */
281    boolean isValue();
282
283    /**
284     * Determines if objects of this type are parented (a parented collection, or an aggregated entity).
285     * 
286     * <p>
287     * In effect, means has got {@link ParentedFacet}.
288     */
289    boolean isParented();
290
291    /**
292     * Determines if objects of this type are either values or aggregated.
293     * 
294     * @see #isValue()
295     * @see #isParented()
296     */
297    boolean isValueOrIsParented();
298
299    /**
300     * Determines if objects of this type can be set up from a text entry
301     * string.
302     * 
303     * <p>
304     * In effect, means has got a {@link ParseableFacet}.
305     */
306    boolean isParseable();
307
308    /**
309     * Determines if objects of this type can be converted to a data-stream.
310     * 
311     * <p>
312     * In effect, means has got {@link EncodableFacet}.
313     */
314    boolean isEncodeable();
315
316    /**
317     * Whether has the {@link ImmutableFacet}.
318     */
319    boolean isImmutable();
320
321    /**
322     * Whether has the {@link HiddenFacet}
323     */
324    boolean isHidden();
325
326    // //////////////////////////////////////////////////////////////
327    // Creation
328    // //////////////////////////////////////////////////////////////
329
330    Object createObject();
331
332    /**
333     * REVIEW: should this behaviour move, eg onto ObjectAdapter?
334     */
335    ObjectAdapter initialize(ObjectAdapter object);
336
337
338
339    // //////////////////////////////////////////////////////////////
340    // Service
341    // //////////////////////////////////////////////////////////////
342
343    /**
344     * Whether or not this specification represents a domain service (as opposed
345     * to a domain entity or a value etc).
346     * 
347     * <p>
348     * <b>WARNING</b>: this only returns <tt>true</tt> once the metamodel has been
349     * fully built, and a <tt>PersistenceSession</tt> has been opened.  This should
350     * probably be improved upon; for now, beware... 
351     */
352    boolean isService();
353
354    public void markAsService();
355
356
357
358
359
360
361
362}