1 /*
2 * Copyright 2007-2008 Naoki NOSE.
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 */
16 package jp.liq.container.component;
17
18 import java.util.ArrayList;
19 import java.util.List;
20
21 import jp.liq.container.Component;
22 import jp.liq.container.Injector;
23 import jp.liq.container.Resolver;
24 import jp.liq.container.reflect.ObjectFactory;
25
26 /**
27 * {@link Injector} を指定することができる、Component の抽象基底クラスです。
28 * @author nosen
29 */
30 public abstract class InjectableComponent<T, C extends InjectableComponent<T, C>> implements Component<T> {
31 private final Class<T> componentType;
32 private final List<Injector> injectors;
33 private final Class<?>[] dependencies;
34 private final boolean recycled;
35 private T instance;
36
37 /**
38 * このクラスのインスタンスを構築します。
39 * @param type コンポーネントの型
40 * @param deps コンポーネントのインスタンス生成時に必要となるクラス
41 */
42 public InjectableComponent(Class<T> type, Class<?>[] deps) {
43 this(type, deps, false);
44 }
45
46 /**
47 * このクラスのインスタンスを構築します。
48 * @param type コンポーネントの型
49 * @param deps コンポーネントのインスタンス生成時に必要となるクラス
50 * @param recycled コンポーネントのインスタンスを再利用する
51 */
52 public InjectableComponent(Class<T> type, Class<?>[] deps, boolean recycled) {
53 this.componentType = type;
54 this.injectors = new ArrayList<Injector>();
55 this.dependencies = deps;
56 this.recycled = recycled;
57 }
58 /**
59 * 自分自身のインスタンスを返却します。
60 * @return this
61 */
62 public abstract C getThis();
63
64 /**
65 * コンポーネントのインスタンスを生成する ObjectFactory
66 * を生成します。
67 * @param resolver ObjectFactoryを生成するのに必要なコンポーネントをここから取得。
68 * @return 生成された ObjectFactory
69 */
70 protected abstract ObjectFactory<T> createObjectFactory(Resolver resolver);
71
72 /**
73 * @see jp.liq.container.Component#getInstance(jp.liq.container.Resolver)
74 */
75 public final T getInstance(Resolver resolver) {
76 if(recycled) {
77 synchronized(this) {
78 if(instance == null) {
79 instance = createInstance(resolver);
80 }
81 }
82 return instance;
83 } else {
84 return createInstance(resolver);
85 }
86 }
87
88 private T createInstance(Resolver resolver) {
89 ObjectFactory<T> of = createObjectFactory(resolver);
90
91 T rv = of.createObject(resolver.resolve(dependencies));
92
93 for (Injector inj : injectors) {
94 inj.inject(rv, resolver);
95 }
96 return rv;
97 }
98
99 /**
100 * このコンポーネントのInjectorを追加します。
101 * ここで指定されたInjectorは、
102 * コンポーネントの初期化時に追加された順番で適用されます。
103 * @param injector 追加する Injector
104 * @return このインスタンス自身。
105 */
106 public final C with(Injector injector) {
107 injectors.add(injector);
108 return getThis();
109 }
110
111 /**
112 * このコンポーネントのクラスを返します。
113 */
114 public Class<T> getType() {
115 return componentType;
116 }
117
118 }