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.mgr; 021 022import java.util.concurrent.Callable; 023 024import org.apache.isis.applib.annotation.ActionSemantics; 025import org.apache.isis.core.commons.components.Injectable; 026import org.apache.isis.core.metamodel.adapter.ObjectAdapter; 027import org.apache.isis.core.metamodel.adapter.ResolveState; 028import org.apache.isis.core.metamodel.adapter.oid.Oid; 029import org.apache.isis.core.metamodel.adapter.oid.TypedOid; 030import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException; 031import org.apache.isis.core.metamodel.adapter.version.Version; 032import org.apache.isis.core.metamodel.spec.ObjectSpecification; 033import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation; 034 035/** 036 * Responsible for managing the {@link ObjectAdapter adapter}s and {@link Oid 037 * identities} for each and every POJO that is being used by the framework. 038 * 039 * <p> 040 * It provides a consistent set of adapters in memory, providing an 041 * {@link ObjectAdapter adapter} for the POJOs that are in use ensuring that the 042 * same object is not loaded twice into memory. 043 * 044 * <p> 045 * Each POJO is given an {@link ObjectAdapter adapter} so that the framework can 046 * work with the POJOs even though it does not understand their types. Each POJO 047 * maps to an {@link ObjectAdapter adapter} and these are reused. 048 */ 049public interface AdapterManager extends Injectable { 050 051 /** 052 * Gets the {@link ObjectAdapter adapter} for the {@link Oid} if it exists 053 * in the identity map. 054 * 055 * @param oid 056 * - must not be <tt>null</tt> 057 * @return adapter, or <tt>null</tt> if doesn't exist. 058 */ 059 ObjectAdapter getAdapterFor(Oid oid); 060 061 /** 062 * Gets the {@link ObjectAdapter adapter} for the specified domain object if 063 * it exists in the identity map. 064 * 065 * <p> 066 * Provided by the <tt>AdapterManager</tt> when used by framework. 067 * 068 * @param pojo 069 * - must not be <tt>null</tt> 070 * @return adapter, or <tt>null</tt> if doesn't exist. 071 */ 072 ObjectAdapter getAdapterFor(Object pojo); 073 074 075 public enum ConcurrencyChecking { 076 NO_CHECK, 077 CHECK; 078 079 public boolean isChecking() { 080 return this == CHECK; 081 } 082 083 public static ConcurrencyChecking concurrencyCheckingFor(ActionSemantics.Of actionSemantics) { 084 return actionSemantics == ActionSemantics.Of.SAFE 085 ? ConcurrencyChecking.NO_CHECK 086 : ConcurrencyChecking.CHECK; 087 } 088 089 /** 090 * Provides a mechanism to temporarily disable concurrency checking. 091 * 092 * <p> 093 * A {@link ThreadLocal} is used because typically there is JDO/DataNucleus code between the Isis code 094 * that wishes to disable the concurrency checking and the code (an Isis callback) that needs to 095 * check if checking has been disabled. 096 */ 097 private static ThreadLocal<ConcurrencyChecking> concurrencyChecking = new ThreadLocal<ConcurrencyChecking>(){ 098 protected ConcurrencyChecking initialValue() { 099 return CHECK; 100 }; 101 }; 102 103 /** 104 * Whether concurrency checking is currently disabled. 105 */ 106 public static boolean isCurrentlyEnabled() { 107 return concurrencyChecking.get().isChecking(); 108 } 109 110 /** 111 * Allows a caller to temporarily disable concurrency checking for the current thread. 112 */ 113 public static <T> T executeWithConcurrencyCheckingDisabled(final Callable<T> callable) { 114 final ConcurrencyChecking prior = ConcurrencyChecking.concurrencyChecking.get(); 115 try { 116 ConcurrencyChecking.concurrencyChecking.set(ConcurrencyChecking.NO_CHECK); 117 return callable.call(); 118 } catch(Exception ex) { 119 throw new RuntimeException(ex); 120 } finally { 121 ConcurrencyChecking.concurrencyChecking.set(prior); 122 } 123 } 124 125 /** 126 * Allows a caller to temporarily disable concurrency checking for the current thread. 127 */ 128 public static void executeWithConcurrencyCheckingDisabled(final Runnable runnable) { 129 final ConcurrencyChecking prior = ConcurrencyChecking.concurrencyChecking.get(); 130 try { 131 ConcurrencyChecking.concurrencyChecking.set(ConcurrencyChecking.NO_CHECK); 132 runnable.run(); 133 } finally { 134 ConcurrencyChecking.concurrencyChecking.set(prior); 135 } 136 } 137 138 139 } 140 141 /** 142 * As per {@link #adapterFor(TypedOid, ConcurrencyChecking)}, with 143 * {@value org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking#NO_CHECK no checking}. 144 * 145 * <p> 146 * This method will <i>always</i> return an object, possibly indicating it is persistent; so make sure that you 147 * know that the oid does indeed represent an object you know exists. 148 * </p> 149 */ 150 ObjectAdapter adapterFor(TypedOid oid); 151 152 153 /** 154 * Either returns an existing {@link ObjectAdapter adapter} (as per 155 * {@link #getAdapterFor(Oid)}), otherwise re-creates an adapter with the 156 * specified (persistent) {@link Oid}. 157 * 158 * <p> 159 * Typically called when the {@link Oid} is already known, that is, when 160 * resolving an already-persisted object. Is also available for 161 * <tt>Memento</tt> support however, so {@link Oid} could also represent a 162 * {@link Oid#isTransient() transient} object. 163 * 164 * <p> 165 * The pojo itself is recreated by delegating to a {@link PojoRecreator} implementation. 166 * The default impl just uses the {@link ObjectSpecification#createObject()}; 167 * however object stores (eg JDO/DataNucleus) can provide alternative implementations 168 * in order to ensure that the created pojo is attached to a persistence context. 169 * 170 * <p> 171 * If the {@link ObjectAdapter adapter} is recreated, its 172 * {@link ResolveState} will be set to {@link ResolveState#GHOST}. 173 * 174 * <p> 175 * The {@link ConcurrencyChecking} parameter determines whether concurrency checking is performed. 176 * If it is requested, then a check is made to ensure that the {@link Oid#getVersion() version} 177 * of the {@link TypedOid oid} of the recreated adapter is the same as that of the provided {@link TypedOid oid}. 178 * If the version differs, then a {@link ConcurrencyException} is thrown. 179 * 180 * <p> 181 * ALSO, even if a {@link ConcurrencyException}, then the provided {@link TypedOid oid}'s {@link Version version} 182 * will be {@link TypedOid#setVersion(org.apache.isis.core.metamodel.adapter.version.Version) set} to the current 183 * value. This allows the client to retry if they wish. 184 * 185 * @throws {@link ObjectNotFoundException} if the object does not exist. 186 */ 187 ObjectAdapter adapterFor(TypedOid oid, ConcurrencyChecking concurrencyChecking); 188 189 /** 190 * Looks up or creates a standalone (value) or root adapter. 191 */ 192 ObjectAdapter adapterFor(Object domainObject); 193 194 /** 195 * Looks up or creates a standalone (value), aggregated or root adapter. 196 */ 197 ObjectAdapter adapterFor(Object domainObject, ObjectAdapter parentAdapter); 198 199 /** 200 * Looks up or creates a collection adapter. 201 */ 202 public ObjectAdapter adapterFor(final Object pojo, final ObjectAdapter parentAdapter, OneToManyAssociation collection); 203 204}