blob: b0b040e74a50233332f17b44d15c87e5196e8f76 [file] [log] [blame]
crazybobleeabc4dd02007-02-01 01:44:36 +00001/**
2 * Copyright (C) 2006 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
crazyboblee63b592b2007-01-25 02:45:24 +000016
17package com.google.inject;
18
kevinb9na2915a92007-02-28 06:20:30 +000019import com.google.inject.util.StackTraceElements;
crazybobleeb1f2e682007-02-15 05:14:32 +000020import java.lang.annotation.Annotation;
crazyboblee278ee4d2007-02-15 19:23:13 +000021import java.util.Map;
crazybobleef33d23e2007-02-12 04:17:48 +000022
crazyboblee63b592b2007-01-25 02:45:24 +000023/**
crazybobleee5fbbb02007-02-05 07:00:27 +000024 * Built in scope implementations.
crazyboblee63b592b2007-01-25 02:45:24 +000025 *
26 * @author crazybob@google.com (Bob Lee)
27 */
crazyboblee68d2f4b2007-02-07 18:47:24 +000028public class Scopes {
29
crazybobleef33d23e2007-02-12 04:17:48 +000030 private Scopes() {}
crazyboblee63b592b2007-01-25 02:45:24 +000031
32 /**
crazyboblee61257a82007-03-03 00:23:40 +000033 * One instance per {@link Injector}. Also see {@code @}{@link Singleton}.
crazyboblee63b592b2007-01-25 02:45:24 +000034 */
kevinb9na2915a92007-02-28 06:20:30 +000035 public static final Scope SINGLETON = new Scope() {
crazybobleebd9544e2007-02-25 20:32:11 +000036 public <T> Provider<T> scope(Key<T> key, final Provider<T> creator) {
37 return new Provider<T>() {
crazybobleee5fbbb02007-02-05 07:00:27 +000038
39 private volatile T instance;
40
crazybobleef33d23e2007-02-12 04:17:48 +000041 // DCL on a volatile is safe as of Java 5, which we obviously require.
kevinb9n6a565c72007-02-11 01:58:33 +000042 @SuppressWarnings("DoubleCheckedLocking")
crazybobleee5fbbb02007-02-05 07:00:27 +000043 public T get() {
crazybobleee5fbbb02007-02-05 07:00:27 +000044 if (instance == null) {
kevinb9na99dca72007-02-11 04:48:57 +000045 /*
46 * Use a pretty coarse lock. We don't want to run into deadlocks
47 * when two threads try to load circularly-dependent objects.
48 * Maybe one of these days we will identify independent graphs of
49 * objects and offer to load them in parallel.
50 */
kevinb9na2915a92007-02-28 06:20:30 +000051 synchronized (Injector.class) {
crazybobleee5fbbb02007-02-05 07:00:27 +000052 if (instance == null) {
53 instance = creator.get();
54 }
55 }
56 }
57 return instance;
58 }
59
60 public String toString() {
kevinb9nda11d0d2007-04-20 15:58:38 +000061 return String.format("%s[%s]", creator, SINGLETON);
crazybobleee5fbbb02007-02-05 07:00:27 +000062 }
63 };
64 }
crazybobleef33d23e2007-02-12 04:17:48 +000065
66 public String toString() {
kevinb9na2915a92007-02-28 06:20:30 +000067 return "Scopes.SINGLETON";
crazybobleef33d23e2007-02-12 04:17:48 +000068 }
crazyboblee68d2f4b2007-02-07 18:47:24 +000069 };
crazybobleef33d23e2007-02-12 04:17:48 +000070
71 /**
kevinb9nb6054822007-03-19 03:17:47 +000072 * No scope; the same as not applying any scope at all. Each time the
73 * Injector obtains an instance of an object with "no scope", it injects this
74 * instance then immediately forgets it. When the next request for the same
75 * binding arrives it will need to obtain the instance over again.
76 *
77 * <p>This exists only in case a class has been annotated with a scope
78 * annotation such as {@link Singleton @Singleton}, and you need to override
79 * this to "no scope" in your binding.
80 */
81 public static final Scope NO_SCOPE = new Scope() {
82 public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
83 return unscoped;
84 }
85 public String toString() {
86 return "Scopes.NO_SCOPE";
87 }
88 };
89
90 /**
crazybobleef33d23e2007-02-12 04:17:48 +000091 * Gets the scope for a type based on its annotations. Returns {@code null}
92 * if none specified.
93 *
94 * @param implementation type
95 * @param scopes map of scope names to scopes
96 * @param errorHandler handles errors
97 */
98 static Scope getScopeForType(Class<?> implementation,
crazybobleeb1f2e682007-02-15 05:14:32 +000099 Map<Class<? extends Annotation>, Scope> scopes,
crazybobleef33d23e2007-02-12 04:17:48 +0000100 ErrorHandler errorHandler) {
crazyboblee97b2cac2007-02-23 22:31:30 +0000101 Class<? extends Annotation> found = null;
crazybobleeb1f2e682007-02-15 05:14:32 +0000102 for (Annotation annotation : implementation.getAnnotations()) {
crazyboblee97b2cac2007-02-23 22:31:30 +0000103 if (isScopeAnnotation(annotation)) {
crazybobleeb1f2e682007-02-15 05:14:32 +0000104 if (found != null) {
crazyboblee97b2cac2007-02-23 22:31:30 +0000105 errorHandler.handle(
106 StackTraceElements.forType(implementation),
107 ErrorMessages.DUPLICATE_SCOPE_ANNOTATIONS,
108 "@" + found.getSimpleName(),
109 "@" + annotation.annotationType().getSimpleName()
110 );
crazybobleeb1f2e682007-02-15 05:14:32 +0000111 } else {
crazyboblee97b2cac2007-02-23 22:31:30 +0000112 found = annotation.annotationType();
crazybobleeb1f2e682007-02-15 05:14:32 +0000113 }
114 }
crazybobleef33d23e2007-02-12 04:17:48 +0000115 }
crazyboblee97b2cac2007-02-23 22:31:30 +0000116
117 return scopes.get(found);
118 }
119
120 static boolean isScopeAnnotation(Annotation annotation) {
121 return isScopeAnnotation(annotation.annotationType());
122 }
123
124 static boolean isScopeAnnotation(Class<? extends Annotation> annotationType) {
125 return annotationType.isAnnotationPresent(ScopeAnnotation.class);
crazybobleef33d23e2007-02-12 04:17:48 +0000126 }
127
128 /**
129 * Scopes an internal factory.
130 */
131 static <T> InternalFactory<? extends T> scope(Key<T> key,
kevinb9na2915a92007-02-28 06:20:30 +0000132 InjectorImpl injector, InternalFactory<? extends T> creator,
crazybobleef33d23e2007-02-12 04:17:48 +0000133 Scope scope) {
crazyboblee97b2cac2007-02-23 22:31:30 +0000134 // No scope does nothing.
135 if (scope == null) {
crazybobleef33d23e2007-02-12 04:17:48 +0000136 return creator;
137 }
crazybobleebd9544e2007-02-25 20:32:11 +0000138 Provider<T> scoped = scope.scope(key,
kevinb9na2915a92007-02-28 06:20:30 +0000139 new ProviderToInternalFactoryAdapter<T>(injector, creator));
crazybobleebd9544e2007-02-25 20:32:11 +0000140 return new InternalFactoryToProviderAdapter<T>(scoped);
crazybobleef33d23e2007-02-12 04:17:48 +0000141 }
kevinb9na99dca72007-02-11 04:48:57 +0000142}