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;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import jp.liq.container.ContainerException.Reason;
22  
23  /**
24   * 任意のクラスのインスタンスを取得します。 
25   * インスタンス化したいクラスに対応する {@link Component} を生成することができる {@link Module} を 
26   * {@link #include(Module)} で追加することによって、{@link #get(Class)}によって
27   * そのクラスのインスタンスを取得することが出来ます。
28   * 
29   * @author nose
30   */
31  public final class Container {
32      private final List<Module> modules;
33  
34      /**
35       * このクラスのインスタンスを構築します。
36       */
37      public Container() {
38          this.modules = new ArrayList<Module>();
39      }
40  
41      /**
42       * 引数で指定したモジュールをこのContainerに追加します。
43       * @param m 追加するモジュール
44       */
45      public void include(Module m) {
46          modules.add(m);
47      }
48  
49      /**
50       * 引数で指定された 親Container が保持する {@link Module}
51       * をこのインスタンスに追加します。
52       * @param container {@link Module} のコピー元の Container
53       */
54      public void include(Container container) {
55          modules.addAll(container.modules);
56      }
57  
58      /**
59       * 引数で指定されたクラスのインスタンスを取得します。
60       * クラスのインスタンスの生成には、{@link #include(Module)} 
61       * によって追加された{@link Module} が生成する {@link Component} が使用されます。
62       * もし、引数で指定されたクラスに対応する{@link Component} を生成することができる{@link Module}
63       * が複数存在する場合、先に追加されたものが優先されます。
64       * @param type
65       *            インスタンスを取得したいクラス
66       * @return 引数で指定されたクラスのインスタンス
67       */
68      public <T> T get(Class<T> type) throws ContainerException {
69          //TODO check if type is null
70          ComponentMetadata cm = getComponentMetadata(type);
71          if (cm == null) {
72              throw new ContainerException(Reason.COMPONENT_NOT_FOUND, type);
73          }
74          ContainerResolver resolver = new ContainerResolver(cm);
75          Object o = resolver.resolve();
76          return type.cast(o);
77      }
78  
79      private <T> ComponentMetadata getComponentMetadata(Class<T> type) {
80          for (Module m : modules) {
81              ComponentMetadata cm = m.getComponentMetadata(type);
82              if (cm != null) {
83                  return cm;
84              }
85          }
86          return null;
87      }
88  
89      private class ContainerResolver extends Resolver {
90  
91          ContainerResolver(ComponentMetadata info) {
92              super(info);
93          }
94  
95          @Override
96          protected ComponentMetadata findComponentMetadata(Class<?> type) {
97              return getComponentMetadata(type);
98          }
99  
100     }
101 }