blob: a637ecaea37de2675ce46f7fd0e590cd9fbf47cf [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
limpbizkit76c24b12008-12-25 04:32:41 +000019import com.google.inject.internal.Errors;
20import com.google.inject.internal.InternalFactory;
21import com.google.inject.internal.Scoping;
22import java.lang.annotation.Annotation;
23
crazyboblee63b592b2007-01-25 02:45:24 +000024/**
limpbizkit76c24b12008-12-25 04:32:41 +000025 * Built-in scope implementations.
crazyboblee63b592b2007-01-25 02:45:24 +000026 *
27 * @author crazybob@google.com (Bob Lee)
28 */
crazyboblee68d2f4b2007-02-07 18:47:24 +000029public class Scopes {
30
crazybobleef33d23e2007-02-12 04:17:48 +000031 private Scopes() {}
crazyboblee63b592b2007-01-25 02:45:24 +000032
33 /**
crazyboblee61257a82007-03-03 00:23:40 +000034 * One instance per {@link Injector}. Also see {@code @}{@link Singleton}.
crazyboblee63b592b2007-01-25 02:45:24 +000035 */
kevinb9na2915a92007-02-28 06:20:30 +000036 public static final Scope SINGLETON = new Scope() {
crazybobleebd9544e2007-02-25 20:32:11 +000037 public <T> Provider<T> scope(Key<T> key, final Provider<T> creator) {
38 return new Provider<T>() {
crazybobleee5fbbb02007-02-05 07:00:27 +000039
40 private volatile T instance;
41
crazybobleef33d23e2007-02-12 04:17:48 +000042 // DCL on a volatile is safe as of Java 5, which we obviously require.
kevinb9n6a565c72007-02-11 01:58:33 +000043 @SuppressWarnings("DoubleCheckedLocking")
crazybobleee5fbbb02007-02-05 07:00:27 +000044 public T get() {
crazybobleee5fbbb02007-02-05 07:00:27 +000045 if (instance == null) {
kevinb9na99dca72007-02-11 04:48:57 +000046 /*
47 * Use a pretty coarse lock. We don't want to run into deadlocks
48 * when two threads try to load circularly-dependent objects.
49 * Maybe one of these days we will identify independent graphs of
50 * objects and offer to load them in parallel.
51 */
limpbizkit70962802008-12-31 01:57:54 +000052 synchronized (InjectorImpl.class) {
crazybobleee5fbbb02007-02-05 07:00:27 +000053 if (instance == null) {
54 instance = creator.get();
55 }
56 }
57 }
58 return instance;
59 }
60
61 public String toString() {
kevinb9nda11d0d2007-04-20 15:58:38 +000062 return String.format("%s[%s]", creator, SINGLETON);
crazybobleee5fbbb02007-02-05 07:00:27 +000063 }
64 };
65 }
crazybobleef33d23e2007-02-12 04:17:48 +000066
limpbizkitc9465f92008-05-31 19:01:54 +000067 @Override public String toString() {
kevinb9na2915a92007-02-28 06:20:30 +000068 return "Scopes.SINGLETON";
crazybobleef33d23e2007-02-12 04:17:48 +000069 }
crazyboblee68d2f4b2007-02-07 18:47:24 +000070 };
crazybobleef33d23e2007-02-12 04:17:48 +000071
72 /**
kevinb9nb6054822007-03-19 03:17:47 +000073 * No scope; the same as not applying any scope at all. Each time the
74 * Injector obtains an instance of an object with "no scope", it injects this
75 * instance then immediately forgets it. When the next request for the same
76 * binding arrives it will need to obtain the instance over again.
77 *
78 * <p>This exists only in case a class has been annotated with a scope
79 * annotation such as {@link Singleton @Singleton}, and you need to override
80 * this to "no scope" in your binding.
limpbizkitc489adf2008-11-18 07:01:33 +000081 *
82 * @since 2.0
kevinb9nb6054822007-03-19 03:17:47 +000083 */
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
limpbizkitb3a8f0b2008-09-05 22:30:40 +000093 /** Scopes an internal factory. */
limpbizkit76c24b12008-12-25 04:32:41 +000094 static <T> InternalFactory<? extends T> scope(Key<T> key, InjectorImpl injector,
95 InternalFactory<? extends T> creator, Scoping scoping) {
96
97 if (scoping.isNoScope()) {
crazybobleef33d23e2007-02-12 04:17:48 +000098 return creator;
99 }
limpbizkit76c24b12008-12-25 04:32:41 +0000100
101 Scope scope = scoping.getScopeInstance();
102
103 Provider<T> scoped
104 = scope.scope(key, new ProviderToInternalFactoryAdapter<T>(injector, creator));
limpbizkit5fb9d922008-10-14 23:35:56 +0000105 return new InternalFactoryToProviderAdapter<T>(
106 Initializables.<Provider<? extends T>>of(scoped));
crazybobleef33d23e2007-02-12 04:17:48 +0000107 }
limpbizkit76c24b12008-12-25 04:32:41 +0000108
109 /**
110 * Replaces annotation scopes with instance scopes using the Injector's annotation-to-instance
111 * map. If the scope annotation has no corresponding instance, an error will be added and unscoped
112 * will be retuned.
113 */
114 static Scoping makeInjectable(Scoping scoping, InjectorImpl injector, Errors errors) {
115 Class<? extends Annotation> scopeAnnotation = scoping.getScopeAnnotation();
116 if (scopeAnnotation == null) {
117 return scoping;
118 }
119
120 Scope scope = injector.state.getScope(scopeAnnotation);
121 if (scope != null) {
122 return Scoping.forInstance(scope);
123 }
124
125 errors.scopeNotFound(scopeAnnotation);
126 return Scoping.UNSCOPED;
127 }
kevinb9na99dca72007-02-11 04:48:57 +0000128}