blob: e839581a6dd1a5b3feea6870c0d092eac6736ecb [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
crazybobleeb1f2e682007-02-15 05:14:32 +000019import java.lang.annotation.Annotation;
crazyboblee278ee4d2007-02-15 19:23:13 +000020import java.util.Map;
crazyboblee9a3861b2007-02-20 03:37:31 +000021import com.google.inject.util.StackTraceElements;
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 /**
crazyboblee278ee4d2007-02-15 19:23:13 +000033 * One instance per container. Also see {@code @}{@link ContainerScoped}.
crazyboblee63b592b2007-01-25 02:45:24 +000034 */
crazyboblee68d2f4b2007-02-07 18:47:24 +000035 public static final Scope CONTAINER = new Scope() {
crazyboblee5746d5d2007-02-18 21:52:24 +000036 public <T> Locator<T> scope(Key<T> key, final Locator<T> creator) {
37 return new Locator<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 */
crazybobleee5fbbb02007-02-05 07:00:27 +000051 synchronized (Container.class) {
52 if (instance == null) {
53 instance = creator.get();
54 }
55 }
56 }
57 return instance;
58 }
59
60 public String toString() {
61 return creator.toString();
62 }
63 };
64 }
crazybobleef33d23e2007-02-12 04:17:48 +000065
66 public String toString() {
crazybobleeb1f2e682007-02-15 05:14:32 +000067 return "Scopes.CONTAINER";
crazybobleef33d23e2007-02-12 04:17:48 +000068 }
crazyboblee68d2f4b2007-02-07 18:47:24 +000069 };
crazybobleef33d23e2007-02-12 04:17:48 +000070
71 /**
72 * Gets the scope for a type based on its annotations. Returns {@code null}
73 * if none specified.
74 *
75 * @param implementation type
76 * @param scopes map of scope names to scopes
77 * @param errorHandler handles errors
78 */
79 static Scope getScopeForType(Class<?> implementation,
crazybobleeb1f2e682007-02-15 05:14:32 +000080 Map<Class<? extends Annotation>, Scope> scopes,
crazybobleef33d23e2007-02-12 04:17:48 +000081 ErrorHandler errorHandler) {
crazyboblee97b2cac2007-02-23 22:31:30 +000082 Class<? extends Annotation> found = null;
crazybobleeb1f2e682007-02-15 05:14:32 +000083 for (Annotation annotation : implementation.getAnnotations()) {
crazyboblee97b2cac2007-02-23 22:31:30 +000084 if (isScopeAnnotation(annotation)) {
crazybobleeb1f2e682007-02-15 05:14:32 +000085 if (found != null) {
crazyboblee97b2cac2007-02-23 22:31:30 +000086 errorHandler.handle(
87 StackTraceElements.forType(implementation),
88 ErrorMessages.DUPLICATE_SCOPE_ANNOTATIONS,
89 "@" + found.getSimpleName(),
90 "@" + annotation.annotationType().getSimpleName()
91 );
crazybobleeb1f2e682007-02-15 05:14:32 +000092 } else {
crazyboblee97b2cac2007-02-23 22:31:30 +000093 found = annotation.annotationType();
crazybobleeb1f2e682007-02-15 05:14:32 +000094 }
95 }
crazybobleef33d23e2007-02-12 04:17:48 +000096 }
crazyboblee97b2cac2007-02-23 22:31:30 +000097
98 return scopes.get(found);
99 }
100
101 static boolean isScopeAnnotation(Annotation annotation) {
102 return isScopeAnnotation(annotation.annotationType());
103 }
104
105 static boolean isScopeAnnotation(Class<? extends Annotation> annotationType) {
106 return annotationType.isAnnotationPresent(ScopeAnnotation.class);
crazybobleef33d23e2007-02-12 04:17:48 +0000107 }
108
109 /**
110 * Scopes an internal factory.
111 */
112 static <T> InternalFactory<? extends T> scope(Key<T> key,
113 ContainerImpl container, InternalFactory<? extends T> creator,
114 Scope scope) {
crazyboblee97b2cac2007-02-23 22:31:30 +0000115 // No scope does nothing.
116 if (scope == null) {
crazybobleef33d23e2007-02-12 04:17:48 +0000117 return creator;
118 }
crazyboblee5746d5d2007-02-18 21:52:24 +0000119 Locator<T> scoped = scope.scope(key,
120 new LocatorToInternalFactoryAdapter<T>(container, creator));
121 return new InternalFactoryToLocatorAdapter<T>(scoped);
crazybobleef33d23e2007-02-12 04:17:48 +0000122 }
kevinb9na99dca72007-02-11 04:48:57 +0000123}