View Javadoc

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 }