/* * Copyright 2012 Jason Miller * * Licensed 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 jj.execution; import javax.inject.Inject; import jj.util.Closer; /** * <p> * Descend from this to the basic management of a contextual resource that * can be used in a try-with-resources * <pre class="brush:java"> * try (Closer closer = resource.enterScope(..something..)) { * // use that resource (presumably in a disconnected part of the system) * resource.current()...; * } * </pre> * * <p> * Don't forget! Descendants of this class should be annotated with * {@link javax.inject.Singleton} or there really is just no point * * <p> * If initialization or cleanup of the resource is needed, see {@link ExecutionLifecycleAware}. * * <p> * Subclasses of this classes act as system-wide thread-scoped context locators for resources, * and can be injected and queried to perform work with those resources. For instance, the * currently executing task can be obtained by calling {@link CurrentTask#current()}. * * @param <T> The type of resource being managed * * @author jason * */ public abstract class ExecutionInstance<T> { // this field is initialized for unit tests, // but gets replaced with the appropriate // instance in the running system @Inject private ExecutionInstanceStorage storage = new ExecutionInstanceStorage(); /** * Provides a scoping mechanism for instances that are related to a specific execution, * such as HTTP state, or the currently executing tasks. */ public final Closer enterScope(final T instance) { assert storage.get(getClass()) == null; storage.set(getClass(), instance); if (instance instanceof ExecutionLifecycleAware) { ((ExecutionLifecycleAware)instance).enteredScope(); } return () -> { storage.clear(ExecutionInstance.this.getClass()); if (instance instanceof ExecutionLifecycleAware) { ((ExecutionLifecycleAware)instance).exitedScope(); } }; } /** * The current instance held in scope, or null if none */ public T current() { return storage.get(getClass()); } }