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}