/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.isis.core.metamodel.adapter.mgr;
import java.util.concurrent.Callable;
import org.apache.isis.applib.annotation.ActionSemantics;
import org.apache.isis.applib.annotation.Programmatic;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.oid.Oid;
import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
public interface AdapterManager extends AdapterManagerBase {
/**
* Gets the {@link ObjectAdapter adapter} for the {@link Oid} if it exists
* in the identity map.
*
* @param oid
* - must not be <tt>null</tt>
* @return adapter, or <tt>null</tt> if doesn't exist.
*/
@Programmatic
ObjectAdapter getAdapterFor(Oid oid);
enum ConcurrencyChecking {
NO_CHECK,
CHECK;
@Programmatic
public boolean isChecking() {
return this == CHECK;
}
public static ConcurrencyChecking concurrencyCheckingFor(ActionSemantics.Of actionSemantics) {
return actionSemantics.isSafeInNature()
? ConcurrencyChecking.NO_CHECK
: ConcurrencyChecking.CHECK;
}
/**
* Provides a mechanism to temporarily disable concurrency checking.
*
* <p>
* A {@link ThreadLocal} is used because typically there is JDO/DataNucleus code between the Isis code
* that wishes to disable the concurrency checking and the code (an Isis callback) that needs to
* check if checking has been disabled.
*/
private static ThreadLocal<ConcurrencyChecking> concurrencyChecking = new ThreadLocal<ConcurrencyChecking>(){
protected ConcurrencyChecking initialValue() {
return CHECK;
};
};
/**
* Whether concurrency checking is currently enabled or disabled.
*/
public static boolean isCurrentlyEnabled() {
return concurrencyChecking.get().isChecking();
}
/**
* Allows a caller to temporarily disable concurrency checking for the current thread.
*/
public static <T> T executeWithConcurrencyCheckingDisabled(final Callable<T> callable) {
ConcurrencyChecking prior = null;
try {
prior = disable();
return callable.call();
} catch(Exception ex) {
throw new RuntimeException(ex);
} finally {
reset(prior);
}
}
/**
* Recommended instead to call {@link #executeWithConcurrencyCheckingDisabled(Runnable)} or {@link #executeWithConcurrencyCheckingDisabled(Callable)}.
*
* <p>
* If this method is used, then make sure to call {@link #reset(ConcurrencyChecking)} afterwards, using the value returned by this method.
* </p>
*
* @return the value of the {@link ConcurrencyChecking} thread-local prior to disabling it (to allow for nested calls).
*/
public static ConcurrencyChecking disable() {
final ConcurrencyChecking prior = ConcurrencyChecking.concurrencyChecking.get();
ConcurrencyChecking.concurrencyChecking.set(ConcurrencyChecking.NO_CHECK);
return prior;
}
public static void reset(ConcurrencyChecking prior) {
if(prior == null) {
return;
}
ConcurrencyChecking.concurrencyChecking.set(prior);
}
/**
* Allows a caller to temporarily disable concurrency checking for the current thread.
*/
public static void executeWithConcurrencyCheckingDisabled(final Runnable runnable) {
final ConcurrencyChecking prior = ConcurrencyChecking.concurrencyChecking.get();
try {
disable();
runnable.run();
} finally {
ConcurrencyChecking.concurrencyChecking.set(prior);
}
}
}
/**
* Looks up or creates a collection adapter.
*/
@Programmatic
ObjectAdapter adapterFor(
final Object pojo,
final ObjectAdapter parentAdapter,
OneToManyAssociation collection);
/**
* Enable RecreatableObjectFacet to 'temporarily' map an existing pojo to an oid.
*/
@Programmatic
ObjectAdapter mapRecreatedPojo(Oid oid, Object recreatedPojo);
/**
* Enable RecreatableObjectFacet to remove a 'temporarily' mapped an adapter for a pojo.
*/
@Programmatic
void removeAdapter(ObjectAdapter adapter);
}