001: /**
002: * Copyright (C) 2006 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */package com.bm.ejb3guice.inject;
016:
017: import com.bm.ejb3guice.internal.StackTraceElements;
018:
019: import java.lang.annotation.Annotation;
020: import java.util.Map;
021:
022: /**
023: * Built in scope implementations.
024: *
025: * @author crazybob@google.com (Bob Lee)
026: */
027: public class Scopes {
028:
029: private Scopes() {
030: }
031:
032: /**
033: * One instance per {@link Injector}. Also see {@code @}{@link Singleton}.
034: */
035: public static final Scope SINGLETON = new Scope() {
036: public <T> Provider<T> scope(Key<T> key,
037: final Provider<T> creator) {
038: return new Provider<T>() {
039:
040: private volatile T instance;
041:
042: // DCL on a volatile is safe as of Java 5, which we obviously require.
043: @SuppressWarnings("DoubleCheckedLocking")
044: public T get() {
045: if (instance == null) {
046: /*
047: * Use a pretty coarse lock. We don't want to run into deadlocks
048: * when two threads try to load circularly-dependent objects.
049: * Maybe one of these days we will identify independent graphs of
050: * objects and offer to load them in parallel.
051: */
052: synchronized (Injector.class) {
053: if (instance == null) {
054: instance = creator.get();
055: }
056: }
057: }
058: return instance;
059: }
060:
061: public String toString() {
062: return String.format("%s[%s]", creator, SINGLETON);
063: }
064: };
065: }
066:
067: public String toString() {
068: return "Scopes.SINGLETON";
069: }
070: };
071:
072: /**
073: * No scope; the same as not applying any scope at all. Each time the
074: * Injector obtains an instance of an object with "no scope", it injects this
075: * instance then immediately forgets it. When the next request for the same
076: * binding arrives it will need to obtain the instance over again.
077: *
078: * <p>This exists only in case a class has been annotated with a scope
079: * annotation such as {@link Singleton @Singleton}, and you need to override
080: * this to "no scope" in your binding.
081: */
082: public static final Scope NO_SCOPE = new Scope() {
083: public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
084: return unscoped;
085: }
086:
087: public String toString() {
088: return "Scopes.NO_SCOPE";
089: }
090: };
091:
092: /**
093: * Gets the scope for a type based on its annotations. Returns {@code null}
094: * if none specified.
095: *
096: * @param implementation type
097: * @param scopes map of scope names to scopes
098: * @param errorHandler handles errors
099: */
100: static Scope getScopeForType(Class<?> implementation,
101: Map<Class<? extends Annotation>, Scope> scopes,
102: ErrorHandler errorHandler) {
103: Class<? extends Annotation> found = null;
104: for (Annotation annotation : implementation.getAnnotations()) {
105: if (isScopeAnnotation(annotation)) {
106: if (found != null) {
107: errorHandler.handle(StackTraceElements
108: .forType(implementation),
109: ErrorMessages.DUPLICATE_SCOPE_ANNOTATIONS,
110: "@" + found.getSimpleName(), "@"
111: + annotation.annotationType()
112: .getSimpleName());
113: } else {
114: found = annotation.annotationType();
115: }
116: }
117: }
118:
119: return scopes.get(found);
120: }
121:
122: static boolean isScopeAnnotation(Annotation annotation) {
123: return isScopeAnnotation(annotation.annotationType());
124: }
125:
126: static boolean isScopeAnnotation(
127: Class<? extends Annotation> annotationType) {
128: return annotationType
129: .isAnnotationPresent(ScopeAnnotation.class);
130: }
131:
132: /**
133: * Scopes an internal factory.
134: */
135: static <T> InternalFactory<? extends T> scope(Key<T> key,
136: InjectorImpl injector,
137: InternalFactory<? extends T> creator, Scope scope) {
138: // No scope does nothing.
139: if (scope == null) {
140: return creator;
141: }
142: Provider<T> scoped = scope.scope(key,
143: new ProviderToInternalFactoryAdapter<T>(injector,
144: creator));
145: return new InternalFactoryToProviderAdapter<T>(scoped);
146: }
147: }
|