| /** |
| * Copyright (C) 2006 Google Inc. |
| * <p> |
| * 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 |
| * </p> |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * <p> |
| * 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. |
| * </p> |
| */ |
| |
| package com.opensymphony.xwork2.inject; |
| |
| import java.util.concurrent.Callable; |
| |
| /** |
| * Scope of an injected objects. |
| * |
| * @author crazybob |
| */ |
| public enum Scope { |
| |
| /** |
| * One instance per injection. |
| */ |
| PROTOTYPE { |
| @Override |
| <T> InternalFactory<? extends T> scopeFactory(Class<T> type, String name, |
| InternalFactory<? extends T> factory) { |
| return InitializableFactory.wrapIfNeeded(factory); |
| } |
| }, |
| |
| /** |
| * One instance per container. |
| */ |
| SINGLETON { |
| @Override |
| <T> InternalFactory<? extends T> scopeFactory(Class<T> type, String name, final InternalFactory<? extends T> factory) { |
| return new InternalFactory<T>() { |
| volatile T instance; |
| |
| public T create(InternalContext context) { |
| if (instance == null) { |
| synchronized (context.getContainer()) { |
| if (instance == null) { |
| instance = InitializableFactory.wrapIfNeeded(factory).create(context); |
| } |
| } |
| } |
| return instance; |
| } |
| |
| @Override |
| public Class<? extends T> type() { |
| return factory.type(); |
| } |
| |
| @Override |
| public String toString() { |
| return factory.toString(); |
| } |
| }; |
| } |
| }, |
| |
| /** |
| * <p> |
| * One instance per thread. |
| * </p> |
| * |
| * <p> |
| * <b>Note:</b> if a thread local object strongly references its {@link |
| * Container}, neither the {@code Container} nor the object will be |
| * eligible for garbage collection, i.e. memory leak. |
| * </p> |
| */ |
| THREAD { |
| @Override |
| <T> InternalFactory<? extends T> scopeFactory(Class<T> type, String name, final InternalFactory<? extends T> factory) { |
| return new InternalFactory<T>() { |
| final ThreadLocal<T> threadLocal = new ThreadLocal<>(); |
| |
| public T create(final InternalContext context) { |
| T t = threadLocal.get(); |
| if (t == null) { |
| t = InitializableFactory.wrapIfNeeded(factory).create(context); |
| threadLocal.set(t); |
| } |
| return t; |
| } |
| |
| @Override |
| public Class<? extends T> type() { |
| return factory.type(); |
| } |
| |
| @Override |
| public String toString() { |
| return factory.toString(); |
| } |
| }; |
| } |
| }, |
| |
| /** |
| * One instance per request. |
| */ |
| REQUEST { |
| @Override |
| <T> InternalFactory<? extends T> scopeFactory(final Class<T> type, final String name, final InternalFactory<? extends T> factory) { |
| return new InternalFactory<T>() { |
| public T create(InternalContext context) { |
| Strategy strategy = context.getScopeStrategy(); |
| try { |
| return strategy.findInRequest( |
| type, name, toCallable(context, factory)); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| @Override |
| public Class<? extends T> type() { |
| return factory.type(); |
| } |
| |
| @Override |
| public String toString() { |
| return factory.toString(); |
| } |
| }; |
| } |
| }, |
| |
| /** |
| * One instance per session. |
| */ |
| SESSION { |
| @Override |
| <T> InternalFactory<? extends T> scopeFactory(final Class<T> type, final String name, final InternalFactory<? extends T> factory) { |
| return new InternalFactory<T>() { |
| public T create(InternalContext context) { |
| Strategy strategy = context.getScopeStrategy(); |
| try { |
| return strategy.findInSession( |
| type, name, toCallable(context, factory)); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| @Override |
| public Class<? extends T> type() { |
| return factory.type(); |
| } |
| |
| @Override |
| public String toString() { |
| return factory.toString(); |
| } |
| }; |
| } |
| }, |
| |
| /** |
| * One instance per wizard. |
| */ |
| WIZARD { |
| @Override |
| <T> InternalFactory<? extends T> scopeFactory(final Class<T> type, final String name, final InternalFactory<? extends T> factory) { |
| return new InternalFactory<T>() { |
| public T create(InternalContext context) { |
| Strategy strategy = context.getScopeStrategy(); |
| try { |
| return strategy.findInWizard( |
| type, name, toCallable(context, factory)); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| @Override |
| public Class<? extends T> type() { |
| return factory.type(); |
| } |
| |
| @Override |
| public String toString() { |
| return factory.toString(); |
| } |
| }; |
| } |
| }; |
| |
| <T> Callable<? extends T> toCallable(final InternalContext context, |
| final InternalFactory<? extends T> factory) { |
| return new Callable<T>() { |
| public T call() throws Exception { |
| return InitializableFactory.wrapIfNeeded(factory).create(context); |
| } |
| }; |
| } |
| |
| /** |
| * Wraps factory with scoping logic. |
| * |
| * @param type type of object |
| * @param name name of object |
| * @param factory factory |
| * |
| * @return the factory for the given type and name |
| */ |
| abstract <T> InternalFactory<? extends T> scopeFactory( |
| Class<T> type, String name, InternalFactory<? extends T> factory); |
| |
| /** |
| * Pluggable scoping strategy. Enables users to provide custom |
| * implementations of request, session, and wizard scopes. Implement and |
| * pass to {@link |
| * Container#setScopeStrategy(com.opensymphony.xwork2.inject.Scope.Strategy)}. |
| */ |
| public interface Strategy { |
| |
| /** |
| * Finds an object for the given type and name in the request scope. |
| * Creates a new object if necessary using the given factory. |
| * |
| * @param <T> generic type |
| * @param type type of object |
| * @param name name of object |
| * @param factory factory |
| * |
| * @return the object for the given type and name in the request scope |
| * |
| * @throws Exception in case of any error |
| */ |
| <T> T findInRequest(Class<T> type, String name, |
| Callable<? extends T> factory) throws Exception; |
| |
| /** |
| * Finds an object for the given type and name in the session scope. |
| * Creates a new object if necessary using the given factory. |
| * |
| * @param <T> generic type |
| * @param type type of object |
| * @param name name of object |
| * @param factory factory |
| * |
| * @return the object for the given type and name in the session scope |
| * |
| * @throws Exception in case of any error |
| */ |
| <T> T findInSession(Class<T> type, String name, |
| Callable<? extends T> factory) throws Exception; |
| |
| /** |
| * Finds an object for the given type and name in the wizard scope. |
| * Creates a new object if necessary using the given factory. |
| * |
| * @param <T> generic type |
| * @param type type of object |
| * @param name name of object |
| * @param factory factory |
| * |
| * @return the object for the given type and name in the wizard scope |
| * |
| * @throws Exception in case of any error |
| */ |
| <T> T findInWizard(Class<T> type, String name, |
| Callable<? extends T> factory) throws Exception; |
| } |
| } |