blob: bb1eff40a25f8380735c2dc9b8b68f5422a8d712 [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
limpbizkit916f5482008-04-16 20:51:14 +000019import com.google.inject.internal.ErrorHandler;
20import com.google.inject.internal.ErrorMessages;
limpbizkitc9465f92008-05-31 19:01:54 +000021import com.google.inject.internal.StackTraceElements;
limpbizkit916f5482008-04-16 20:51:14 +000022
crazybobleeb1f2e682007-02-15 05:14:32 +000023import java.lang.annotation.Annotation;
crazyboblee278ee4d2007-02-15 19:23:13 +000024import java.util.Map;
crazybobleef33d23e2007-02-12 04:17:48 +000025
crazyboblee63b592b2007-01-25 02:45:24 +000026/**
crazybobleee5fbbb02007-02-05 07:00:27 +000027 * Built in scope implementations.
crazyboblee63b592b2007-01-25 02:45:24 +000028 *
29 * @author crazybob@google.com (Bob Lee)
30 */
crazyboblee68d2f4b2007-02-07 18:47:24 +000031public class Scopes {
32
crazybobleef33d23e2007-02-12 04:17:48 +000033 private Scopes() {}
crazyboblee63b592b2007-01-25 02:45:24 +000034
35 /**
crazyboblee61257a82007-03-03 00:23:40 +000036 * One instance per {@link Injector}. Also see {@code @}{@link Singleton}.
crazyboblee63b592b2007-01-25 02:45:24 +000037 */
kevinb9na2915a92007-02-28 06:20:30 +000038 public static final Scope SINGLETON = new Scope() {
crazybobleebd9544e2007-02-25 20:32:11 +000039 public <T> Provider<T> scope(Key<T> key, final Provider<T> creator) {
40 return new Provider<T>() {
crazybobleee5fbbb02007-02-05 07:00:27 +000041
42 private volatile T instance;
43
crazybobleef33d23e2007-02-12 04:17:48 +000044 // DCL on a volatile is safe as of Java 5, which we obviously require.
kevinb9n6a565c72007-02-11 01:58:33 +000045 @SuppressWarnings("DoubleCheckedLocking")
crazybobleee5fbbb02007-02-05 07:00:27 +000046 public T get() {
crazybobleee5fbbb02007-02-05 07:00:27 +000047 if (instance == null) {
kevinb9na99dca72007-02-11 04:48:57 +000048 /*
49 * Use a pretty coarse lock. We don't want to run into deadlocks
50 * when two threads try to load circularly-dependent objects.
51 * Maybe one of these days we will identify independent graphs of
52 * objects and offer to load them in parallel.
53 */
kevinb9na2915a92007-02-28 06:20:30 +000054 synchronized (Injector.class) {
crazybobleee5fbbb02007-02-05 07:00:27 +000055 if (instance == null) {
56 instance = creator.get();
57 }
58 }
59 }
60 return instance;
61 }
62
63 public String toString() {
kevinb9nda11d0d2007-04-20 15:58:38 +000064 return String.format("%s[%s]", creator, SINGLETON);
crazybobleee5fbbb02007-02-05 07:00:27 +000065 }
66 };
67 }
crazybobleef33d23e2007-02-12 04:17:48 +000068
limpbizkitc9465f92008-05-31 19:01:54 +000069 @Override public String toString() {
kevinb9na2915a92007-02-28 06:20:30 +000070 return "Scopes.SINGLETON";
crazybobleef33d23e2007-02-12 04:17:48 +000071 }
crazyboblee68d2f4b2007-02-07 18:47:24 +000072 };
crazybobleef33d23e2007-02-12 04:17:48 +000073
74 /**
kevinb9nb6054822007-03-19 03:17:47 +000075 * No scope; the same as not applying any scope at all. Each time the
76 * Injector obtains an instance of an object with "no scope", it injects this
77 * instance then immediately forgets it. When the next request for the same
78 * binding arrives it will need to obtain the instance over again.
79 *
80 * <p>This exists only in case a class has been annotated with a scope
81 * annotation such as {@link Singleton @Singleton}, and you need to override
82 * this to "no scope" in your binding.
83 */
84 public static final Scope NO_SCOPE = new Scope() {
85 public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
86 return unscoped;
87 }
limpbizkitc9465f92008-05-31 19:01:54 +000088 @Override public String toString() {
kevinb9nb6054822007-03-19 03:17:47 +000089 return "Scopes.NO_SCOPE";
90 }
91 };
92
93 /**
crazybobleef33d23e2007-02-12 04:17:48 +000094 * Gets the scope for a type based on its annotations. Returns {@code null}
95 * if none specified.
96 *
97 * @param implementation type
98 * @param scopes map of scope names to scopes
99 * @param errorHandler handles errors
100 */
101 static Scope getScopeForType(Class<?> implementation,
crazybobleeb1f2e682007-02-15 05:14:32 +0000102 Map<Class<? extends Annotation>, Scope> scopes,
crazybobleef33d23e2007-02-12 04:17:48 +0000103 ErrorHandler errorHandler) {
crazyboblee97b2cac2007-02-23 22:31:30 +0000104 Class<? extends Annotation> found = null;
crazybobleeb1f2e682007-02-15 05:14:32 +0000105 for (Annotation annotation : implementation.getAnnotations()) {
crazyboblee97b2cac2007-02-23 22:31:30 +0000106 if (isScopeAnnotation(annotation)) {
crazybobleeb1f2e682007-02-15 05:14:32 +0000107 if (found != null) {
crazyboblee97b2cac2007-02-23 22:31:30 +0000108 errorHandler.handle(
109 StackTraceElements.forType(implementation),
110 ErrorMessages.DUPLICATE_SCOPE_ANNOTATIONS,
111 "@" + found.getSimpleName(),
112 "@" + annotation.annotationType().getSimpleName()
113 );
crazybobleeb1f2e682007-02-15 05:14:32 +0000114 } else {
crazyboblee97b2cac2007-02-23 22:31:30 +0000115 found = annotation.annotationType();
crazybobleeb1f2e682007-02-15 05:14:32 +0000116 }
117 }
crazybobleef33d23e2007-02-12 04:17:48 +0000118 }
crazyboblee97b2cac2007-02-23 22:31:30 +0000119
120 return scopes.get(found);
121 }
122
123 static boolean isScopeAnnotation(Annotation annotation) {
124 return isScopeAnnotation(annotation.annotationType());
125 }
126
127 static boolean isScopeAnnotation(Class<? extends Annotation> annotationType) {
128 return annotationType.isAnnotationPresent(ScopeAnnotation.class);
crazybobleef33d23e2007-02-12 04:17:48 +0000129 }
130
131 /**
132 * Scopes an internal factory.
133 */
134 static <T> InternalFactory<? extends T> scope(Key<T> key,
kevinb9na2915a92007-02-28 06:20:30 +0000135 InjectorImpl injector, InternalFactory<? extends T> creator,
crazybobleef33d23e2007-02-12 04:17:48 +0000136 Scope scope) {
crazyboblee97b2cac2007-02-23 22:31:30 +0000137 // No scope does nothing.
crazybobleed0c4b8b2007-09-06 02:47:04 +0000138 if (scope == null || scope == Scopes.NO_SCOPE) {
crazybobleef33d23e2007-02-12 04:17:48 +0000139 return creator;
140 }
crazybobleebd9544e2007-02-25 20:32:11 +0000141 Provider<T> scoped = scope.scope(key,
kevinb9na2915a92007-02-28 06:20:30 +0000142 new ProviderToInternalFactoryAdapter<T>(injector, creator));
crazybobleebd9544e2007-02-25 20:32:11 +0000143 return new InternalFactoryToProviderAdapter<T>(scoped);
crazybobleef33d23e2007-02-12 04:17:48 +0000144 }
kevinb9na99dca72007-02-11 04:48:57 +0000145}