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.adapter;
021
022import java.util.List;
023
024import com.google.common.base.Function;
025import com.google.common.collect.Lists;
026
027import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
028import org.apache.isis.core.metamodel.adapter.oid.AggregatedOid;
029import org.apache.isis.core.metamodel.adapter.oid.CollectionOid;
030import org.apache.isis.core.metamodel.adapter.oid.Oid;
031import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
032import org.apache.isis.core.metamodel.adapter.version.Version;
033import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
034import org.apache.isis.core.metamodel.spec.ElementSpecificationProvider;
035import org.apache.isis.core.metamodel.spec.Instance;
036import org.apache.isis.core.metamodel.spec.ObjectSpecification;
037import org.apache.isis.core.metamodel.spec.Specification;
038
039/**
040 * Adapters to domain objects, where the application is written in terms of
041 * domain objects and those objects are represented within the NOF through these
042 * adapter, and not directly.
043 */
044public interface ObjectAdapter extends Instance, org.apache.isis.applib.annotation.When.Persistable {
045
046    
047    /**
048     * Refines {@link Instance#getSpecification()}.
049     */
050    @Override
051    ObjectSpecification getSpecification();
052
053    /**
054     * Returns the adapted domain object, the POJO, that this adapter represents
055     * with the framework.
056     */
057    Object getObject();
058
059    /**
060     * Returns the title to display this object with, usually obtained from
061     * the wrapped {@link #getObject() domain object}.
062     * 
063     * @deprecated - use {@link #titleString(ObjectAdapter)}
064     */
065    @Deprecated
066    String titleString();
067
068    /**
069     * Returns the title to display this object with, rendered within the context
070     * of some other adapter.
071     * 
072     * <p>
073     * @see TitleFacet#title(ObjectAdapter, ObjectAdapter, org.apache.isis.applib.profiles.Localization)
074     */
075    String titleString(ObjectAdapter contextAdapter);
076
077    /**
078     * Return an {@link Instance} of the specified {@link Specification} with
079     * respect to this {@link ObjectAdapter}.
080     * 
081     * <p>
082     * If called with {@link ObjectSpecification}, then just returns
083     * <tt>this</tt>). If called for other subinterfaces, then should provide an
084     * appropriate {@link Instance} implementation.
085     * 
086     * <p>
087     * Designed to be called in a double-dispatch design from
088     * {@link Specification#getInstance(ObjectAdapter)}.
089     * 
090     * <p>
091     * Note: this method will throw an {@link UnsupportedOperationException}
092     * unless the extended <tt>PojoAdapterXFactory</tt> is configured. (That is,
093     * only <tt>PojoAdapterX</tt> provides support for this; the regular
094     * <tt>PojoAdapter</tt> does not currently.
095     * 
096     * @param adapter
097     * @return
098     */
099    Instance getInstance(Specification specification);
100
101    /**
102     * Sometimes it is necessary to manage the replacement of the underlying
103     * domain object (by another component such as an object store). This method
104     * allows the adapter to be kept while the domain object is replaced.
105     */
106    void replacePojo(Object pojo);
107
108    /**
109     * For (stand-alone) collections, returns the element type.
110     * 
111     * <p>
112     * For owned (aggregated) collections, the element type can be determined
113     * from the <tt>TypeOfFacet</tt> associated with the
114     * <tt>ObjectAssociation</tt> representing the collection.
115     * 
116     * @see #setElementSpecificationProvider(ElementSpecificationProvider)
117     */
118    ObjectSpecification getElementSpecification();
119
120    /**
121     * For (stand-alone) collections, returns the element type.
122     * 
123     * @see #getElementSpecification()
124     */
125    void setElementSpecificationProvider(ElementSpecificationProvider elementSpecificationProvider);
126
127    
128    
129    
130    /**
131     * Returns the name of an icon to use if this object is to be displayed
132     * graphically.
133     * 
134     * <p>
135     * May return <code>null</code> if no icon is specified.
136     */
137    String getIconName();
138
139    /**
140     * Changes the 'lazy loaded' state of the domain object.
141     * 
142     * @see ResolveState
143     */
144    void changeState(ResolveState newState);
145
146    /**
147     * Checks the version of this adapter to make sure that it does not differ
148     * from the specified version.
149     * 
150     * @throws ConcurrencyException
151     *             if the specified version differs from the version held this
152     *             adapter.
153     */
154    void checkLock(Version version);
155
156    /**
157     * The object's unique {@link Oid}. 
158     * 
159     * <p>
160     * This id allows the object to added to, stored by,
161     * and retrieved from the object store.  Objects can be looked up by their
162     * {@link Oid} from the {@link AdapterManager}.
163     * 
164     * <p>
165     * Note that standalone value objects ("foobar", or 5, or a date),
166     * are not mapped and have a <tt>null</tt> oid.
167     */
168    Oid getOid();
169
170    /**
171     * Since {@link Oid}s are now immutable, it is the reference from the 
172     * {@link ObjectAdapter} to its {@link Oid} that must now be updated. 
173     */
174    void replaceOid(Oid persistedOid);
175
176    /**
177     * Determines what 'lazy loaded' state the domain object is in.
178     * 
179     * @see ResolveState
180     */
181    ResolveState getResolveState();
182
183
184    /**
185     * Whether the object is persisted.
186     * 
187     * <p>
188     * Note: not necessarily the reciprocal of {@link #isTransient()};
189     * standalone adapters (with {@link ResolveState#VALUE}) report as neither
190     * persistent or transient.
191     */
192    boolean representsPersistent();
193
194    boolean isNew();
195    boolean isTransient();
196
197    boolean isGhost();
198    boolean isResolved();
199
200    boolean isResolving();
201    boolean isUpdating();
202
203    boolean isDestroyed();
204
205
206    boolean canTransitionToResolving();
207    boolean isTitleAvailable();
208    void markAsResolvedIfPossible();
209
210    
211    
212    Version getVersion();
213
214    void setVersion(Version version);
215
216    void fireChangedEvent();
217
218    /**
219     * Whether this instance belongs to another object (meaning its
220     * {@link #getOid()} will be <tt>ParentedOid</tt>, either an 
221     * {@link AggregatedOid} or a {@link CollectionOid}).
222     */
223    boolean isParented();
224
225    /**
226     * Whether this is an aggregated Oid.
227     */
228    boolean isAggregated();
229
230    /**
231     * Whether this is a value (standalone, has no oid).
232     */
233    boolean isValue();
234
235
236    /**
237     * Either the aggregate root (either itself or, if parented, then its parent adapter).
238     * 
239     * TODO: should this be recursive, to support root->aggregate->aggregate etc.
240     */
241    ObjectAdapter getAggregateRoot();
242
243    boolean respondToChangesInPersistentObjects();
244
245
246    
247    
248    public final class Util {
249
250        private Util() {
251        }
252
253
254        public static Object unwrap(final ObjectAdapter adapter) {
255            return adapter != null ? adapter.getObject() : null;
256        }
257
258        public static Object[] unwrap(final ObjectAdapter[] adapters) {
259            if (adapters == null) {
260                return null;
261            }
262            final Object[] unwrappedObjects = new Object[adapters.length];
263            int i = 0;
264            for (final ObjectAdapter adapter : adapters) {
265                unwrappedObjects[i++] = unwrap(adapter);
266            }
267            return unwrappedObjects;
268        }
269
270        public static List<Object> unwrap(final List<ObjectAdapter> adapters) {
271            List<Object> objects = Lists.newArrayList();
272            for (ObjectAdapter adapter : adapters) {
273                objects.add(unwrap(adapter));
274            }
275            return objects;
276        }
277
278        @SuppressWarnings("unchecked")
279        public static <T> List<T> unwrapT(final List<ObjectAdapter> adapters) {
280            return (List<T>) unwrap(adapters);
281        }
282
283        public static String unwrapAsString(final ObjectAdapter adapter) {
284            final Object obj = unwrap(adapter);
285            if (obj == null) {
286                return null;
287            }
288            if (!(obj instanceof String)) {
289                return null;
290            }
291            return (String) obj;
292        }
293
294        public static String titleString(final ObjectAdapter adapter) {
295            return adapter != null ? adapter.titleString(null) : "";
296        }
297
298        public static boolean exists(final ObjectAdapter adapter) {
299            return adapter != null && adapter.getObject() != null;
300        }
301
302        public static boolean wrappedEqual(final ObjectAdapter adapter1, final ObjectAdapter adapter2) {
303            final boolean defined1 = exists(adapter1);
304            final boolean defined2 = exists(adapter2);
305            if (defined1 && !defined2) {
306                return false;
307            }
308            if (!defined1 && defined2) {
309                return false;
310            }
311            if (!defined1 && !defined2) {
312                return true;
313            } // both null
314            return adapter1.getObject().equals(adapter2.getObject());
315        }
316
317        public static boolean nullSafeEquals(final Object obj1, final Object obj2) {
318            if (obj1 == null && obj2 == null) {
319                return true;
320            }
321            if (obj1 == null || obj2 == null) {
322                return false;
323            }
324            if (obj1.equals(obj2)) {
325                return true;
326            }
327            if (obj1 instanceof ObjectAdapter && obj2 instanceof ObjectAdapter) {
328                final ObjectAdapter adapterObj1 = (ObjectAdapter) obj1;
329                final ObjectAdapter adapterObj2 = (ObjectAdapter) obj2;
330                return nullSafeEquals(adapterObj1.getObject(), adapterObj2.getObject());
331            }
332            return false;
333        }
334
335    }
336
337    
338    public static class Functions {
339        
340        private Functions(){}
341
342        public static Function<ObjectAdapter, Object> getObject() {
343            return new Function<ObjectAdapter, Object>() {
344                @Override
345                public Object apply(ObjectAdapter input) {
346                    return Util.unwrap(input);
347                }
348            };
349        }
350        
351        public static Function<Object, ObjectAdapter> adapterForUsing(final AdapterManager adapterManager) {
352            return new Function<Object, ObjectAdapter>() {
353                @Override
354                public ObjectAdapter apply(final Object pojo) {
355                    return adapterManager.adapterFor(pojo);
356                }
357            };
358        }
359    }
360
361
362}