crazyboblee | abc4dd0 | 2007-02-01 01:44:36 +0000 | [diff] [blame] | 1 | /** |
| 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 | */ |
crazyboblee | 63b592b | 2007-01-25 02:45:24 +0000 | [diff] [blame] | 16 | |
| 17 | package com.google.inject; |
| 18 | |
crazyboblee | f33d23e | 2007-02-12 04:17:48 +0000 | [diff] [blame^] | 19 | import java.lang.annotation.Annotation; |
| 20 | import java.util.Map; |
| 21 | |
crazyboblee | 63b592b | 2007-01-25 02:45:24 +0000 | [diff] [blame] | 22 | /** |
crazyboblee | e5fbbb0 | 2007-02-05 07:00:27 +0000 | [diff] [blame] | 23 | * Built in scope implementations. |
crazyboblee | 63b592b | 2007-01-25 02:45:24 +0000 | [diff] [blame] | 24 | * |
| 25 | * @author crazybob@google.com (Bob Lee) |
| 26 | */ |
crazyboblee | 68d2f4b | 2007-02-07 18:47:24 +0000 | [diff] [blame] | 27 | public class Scopes { |
| 28 | |
crazyboblee | f33d23e | 2007-02-12 04:17:48 +0000 | [diff] [blame^] | 29 | private Scopes() {} |
crazyboblee | 63b592b | 2007-01-25 02:45:24 +0000 | [diff] [blame] | 30 | |
| 31 | /** |
crazyboblee | 68d2f4b | 2007-02-07 18:47:24 +0000 | [diff] [blame] | 32 | * Name of the default scope. |
crazyboblee | 63b592b | 2007-01-25 02:45:24 +0000 | [diff] [blame] | 33 | */ |
crazyboblee | 68d2f4b | 2007-02-07 18:47:24 +0000 | [diff] [blame] | 34 | public static final String DEFAULT_NAME = "DEFAULT"; |
| 35 | |
| 36 | /** |
| 37 | * The default scope, one instance per injection. |
| 38 | */ |
| 39 | public static final Scope DEFAULT = new Scope() { |
crazyboblee | e5fbbb0 | 2007-02-05 07:00:27 +0000 | [diff] [blame] | 40 | public <T> Factory<T> scope(Key<T> key, Factory<T> creator) { |
| 41 | return creator; |
| 42 | } |
crazyboblee | f33d23e | 2007-02-12 04:17:48 +0000 | [diff] [blame^] | 43 | |
| 44 | public String toString() { |
| 45 | return DEFAULT_NAME; |
| 46 | } |
crazyboblee | 68d2f4b | 2007-02-07 18:47:24 +0000 | [diff] [blame] | 47 | }; |
| 48 | |
| 49 | /** |
| 50 | * Name of container scope. |
| 51 | */ |
| 52 | public static final String CONTAINER_NAME = "CONTAINER"; |
crazyboblee | 63b592b | 2007-01-25 02:45:24 +0000 | [diff] [blame] | 53 | |
| 54 | /** |
crazyboblee | baaaf2d | 2007-02-07 03:35:09 +0000 | [diff] [blame] | 55 | * One instance per container. |
crazyboblee | 63b592b | 2007-01-25 02:45:24 +0000 | [diff] [blame] | 56 | */ |
crazyboblee | 68d2f4b | 2007-02-07 18:47:24 +0000 | [diff] [blame] | 57 | public static final Scope CONTAINER = new Scope() { |
crazyboblee | e5fbbb0 | 2007-02-05 07:00:27 +0000 | [diff] [blame] | 58 | public <T> Factory<T> scope(Key<T> key, final Factory<T> creator) { |
| 59 | return new Factory<T>() { |
| 60 | |
| 61 | private volatile T instance; |
| 62 | |
crazyboblee | f33d23e | 2007-02-12 04:17:48 +0000 | [diff] [blame^] | 63 | // DCL on a volatile is safe as of Java 5, which we obviously require. |
kevinb9n | 6a565c7 | 2007-02-11 01:58:33 +0000 | [diff] [blame] | 64 | @SuppressWarnings("DoubleCheckedLocking") |
crazyboblee | e5fbbb0 | 2007-02-05 07:00:27 +0000 | [diff] [blame] | 65 | public T get() { |
crazyboblee | e5fbbb0 | 2007-02-05 07:00:27 +0000 | [diff] [blame] | 66 | if (instance == null) { |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 67 | /* |
| 68 | * Use a pretty coarse lock. We don't want to run into deadlocks |
| 69 | * when two threads try to load circularly-dependent objects. |
| 70 | * Maybe one of these days we will identify independent graphs of |
| 71 | * objects and offer to load them in parallel. |
| 72 | */ |
crazyboblee | e5fbbb0 | 2007-02-05 07:00:27 +0000 | [diff] [blame] | 73 | synchronized (Container.class) { |
| 74 | if (instance == null) { |
| 75 | instance = creator.get(); |
| 76 | } |
| 77 | } |
| 78 | } |
| 79 | return instance; |
| 80 | } |
| 81 | |
| 82 | public String toString() { |
| 83 | return creator.toString(); |
| 84 | } |
| 85 | }; |
| 86 | } |
crazyboblee | f33d23e | 2007-02-12 04:17:48 +0000 | [diff] [blame^] | 87 | |
| 88 | public String toString() { |
| 89 | return CONTAINER_NAME; |
| 90 | } |
crazyboblee | 68d2f4b | 2007-02-07 18:47:24 +0000 | [diff] [blame] | 91 | }; |
crazyboblee | f33d23e | 2007-02-12 04:17:48 +0000 | [diff] [blame^] | 92 | |
| 93 | /** |
| 94 | * 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, |
| 102 | Map<String, Scope> scopes, ErrorHandler errorHandler) { |
| 103 | return getScopeForName( |
| 104 | getScopeNameForType(implementation, errorHandler), |
| 105 | scopes, |
| 106 | errorHandler |
| 107 | ); |
| 108 | |
| 109 | } |
| 110 | |
| 111 | /** |
| 112 | * Finds scope for the given name. Returns {@code null} if the name is |
| 113 | * {@code null}. Otherwise, records an error if a scope isn't found. |
| 114 | */ |
| 115 | static Scope getScopeForName(String name, Map<String, Scope> scopes, |
| 116 | ErrorHandler errorHandler) { |
| 117 | // None found. |
| 118 | if (name == null) { |
| 119 | return null; |
| 120 | } |
| 121 | |
| 122 | // Look up scope for name. |
| 123 | Scope scope = scopes.get(name); |
| 124 | if (scope == null) { |
| 125 | errorHandler.handle( |
| 126 | ErrorMessages.SCOPE_NOT_FOUND, name, scopes.keySet()); |
| 127 | } |
| 128 | return scope; |
| 129 | } |
| 130 | |
| 131 | /** |
| 132 | * Gets the scope name from annotations on the given type. Records errors if |
| 133 | * multiple names are found. |
| 134 | */ |
| 135 | static String getScopeNameForType(Class<?> implementation, |
| 136 | ErrorHandler errorHandler) { |
| 137 | // The first name and annotation type we come to. We hold on to the |
| 138 | // annotation type in case we need it in an error message. |
| 139 | String firstName = null; |
| 140 | Class<? extends Annotation> firstType = null; |
| 141 | |
| 142 | for (Annotation annotation : implementation.getAnnotations()) { |
| 143 | // Look for @Scoped on the class itself and on annotations. |
| 144 | Scoped scoped = findScoped(annotation); |
| 145 | |
| 146 | // If we found an @Scoped, record its value or an error if we already |
| 147 | // recorded a value. |
| 148 | if (scoped != null) { |
| 149 | String name = scoped.value(); |
| 150 | Class<? extends Annotation> type = annotation.annotationType(); |
| 151 | if (firstName == null) { |
| 152 | firstName = name; |
| 153 | firstType = type; |
| 154 | } else { |
| 155 | // Scope already set. |
| 156 | errorHandler.handle(ErrorMessages.SCOPE_ALREADY_SET_BY_ANNOTATION, |
| 157 | implementation, type.getSimpleName(), name, |
| 158 | firstType.getSimpleName(), firstName); |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | return firstName; |
| 164 | } |
| 165 | |
| 166 | /** |
| 167 | * The given annotation may be an instance of {@code Scoped} or it may be |
| 168 | * annotated with {@code Scoped}. |
| 169 | */ |
| 170 | static Scoped findScoped(Annotation annotation) { |
| 171 | Class<? extends Annotation> annotationType = annotation.annotationType(); |
| 172 | return annotationType == Scoped.class |
| 173 | ? (Scoped) annotation |
| 174 | : annotationType.getAnnotation(Scoped.class); |
| 175 | } |
| 176 | |
| 177 | /** |
| 178 | * Scopes an internal factory. |
| 179 | */ |
| 180 | static <T> InternalFactory<? extends T> scope(Key<T> key, |
| 181 | ContainerImpl container, InternalFactory<? extends T> creator, |
| 182 | Scope scope) { |
| 183 | // Default scope does nothing. |
| 184 | if (scope == null || scope == DEFAULT) { |
| 185 | return creator; |
| 186 | } |
| 187 | |
| 188 | Factory<T> scoped = scope.scope(key, |
| 189 | new FactoryToInternalFactoryAdapter<T>(container, creator)); |
| 190 | return new InternalFactoryToFactoryAdapter<T>(scoped); |
| 191 | } |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 192 | } |