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.google.inject;
016:
017: import com.google.inject.util.StackTraceElements;
018: import java.lang.annotation.Annotation;
019: import java.util.Map;
020:
021: /**
022: * Built in scope implementations.
023: *
024: * @author crazybob@google.com (Bob Lee)
025: */
026: public class Scopes {
027:
028: private Scopes() {
029: }
030:
031: /**
032: * One instance per {@link Injector}. Also see {@code @}{@link Singleton}.
033: */
034: public static final Scope SINGLETON = new Scope() {
035: public <T> Provider<T> scope(Key<T> key,
036: final Provider<T> creator) {
037: return new Provider<T>() {
038:
039: private volatile T instance;
040:
041: // DCL on a volatile is safe as of Java 5, which we obviously require.
042: @SuppressWarnings("DoubleCheckedLocking")
043: public T get() {
044: if (instance == null) {
045: /*
046: * Use a pretty coarse lock. We don't want to run into deadlocks
047: * when two threads try to load circularly-dependent objects.
048: * Maybe one of these days we will identify independent graphs of
049: * objects and offer to load them in parallel.
050: */
051: synchronized (Injector.class) {
052: if (instance == null) {
053: instance = creator.get();
054: }
055: }
056: }
057: return instance;
058: }
059:
060: public String toString() {
061: return creator.toString();
062: }
063: };
064: }
065:
066: public String toString() {
067: return "Scopes.SINGLETON";
068: }
069: };
070:
071: /**
072: * Gets the scope for a type based on its annotations. Returns {@code null}
073: * if none specified.
074: *
075: * @param implementation type
076: * @param scopes map of scope names to scopes
077: * @param errorHandler handles errors
078: */
079: static Scope getScopeForType(Class<?> implementation,
080: Map<Class<? extends Annotation>, Scope> scopes,
081: ErrorHandler errorHandler) {
082: Class<? extends Annotation> found = null;
083: for (Annotation annotation : implementation.getAnnotations()) {
084: if (isScopeAnnotation(annotation)) {
085: if (found != null) {
086: errorHandler.handle(StackTraceElements
087: .forType(implementation),
088: ErrorMessages.DUPLICATE_SCOPE_ANNOTATIONS,
089: "@" + found.getSimpleName(), "@"
090: + annotation.annotationType()
091: .getSimpleName());
092: } else {
093: found = annotation.annotationType();
094: }
095: }
096: }
097:
098: return scopes.get(found);
099: }
100:
101: static boolean isScopeAnnotation(Annotation annotation) {
102: return isScopeAnnotation(annotation.annotationType());
103: }
104:
105: static boolean isScopeAnnotation(
106: Class<? extends Annotation> annotationType) {
107: return annotationType
108: .isAnnotationPresent(ScopeAnnotation.class);
109: }
110:
111: /**
112: * Scopes an internal factory.
113: */
114: static <T> InternalFactory<? extends T> scope(Key<T> key,
115: InjectorImpl injector,
116: InternalFactory<? extends T> creator, Scope scope) {
117: // No scope does nothing.
118: if (scope == null) {
119: return creator;
120: }
121: Provider<T> scoped = scope.scope(key,
122: new ProviderToInternalFactoryAdapter<T>(injector,
123: creator));
124: return new InternalFactoryToProviderAdapter<T>(scoped);
125: }
126: }
|