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.Stack;
19  
20  import jp.liq.container.ContainerException.Reason;
21  
22  /**
23   * あるクラスのインスタンスを生成する際に必要となる、他のクラスのインスタンスを生成します。
24   * @see Component#getInstance(Resolver)
25   * @see Injector#inject(Object, Resolver)
26   * @author nose
27   */
28  public abstract class Resolver {
29      private final Stack<ComponentMetadata> resolvingComponents;
30  
31      Resolver(ComponentMetadata root) {
32          resolvingComponents = new Stack<ComponentMetadata>();
33          resolvingComponents.push(root);
34      }
35  
36      final Object resolve() {
37          return resolvingComponents.get(0).getComponent().getInstance(this);
38      }
39  
40      /**
41       * 引数で指定されたクラスのインスタンスを生成します。
42       * インスタンス生成の方法は{@link Container#get(Class)}と同じですが、
43       * このメソッドでは、クラスの依存関係を追跡し、循環参照が発生した場合、
44       * CircularReferenceExceptionをスローします。
45       * @param type インスタンスを取得したいクラス
46       * @return 見つかったコンポーネント
47       */
48      public final <T> T resolve(Class<T> type)
49          throws ContainerException {
50          ComponentMetadata c = findComponentMetadata(type);
51  
52          if(c != null) {
53              if (resolvingComponents.contains(c)) {
54                  throw new ContainerException(Reason.CIRCULAR_REFERENCE, type,
55                          getDependencyPathStr(resolvingComponents));
56              }
57              resolvingComponents.push(c);
58              Object o = c.getComponent().getInstance(this);
59              resolvingComponents.pop();
60              return type.cast(o);
61          }
62  
63          throw new ContainerException(Reason.MISSING_DEPENDENCY, type, getDependencyPathStr(resolvingComponents));
64  
65      }
66  
67      /**
68       * 引数で指定されたクラスの配列に対応するインスタンスを生成し、
69       * オブジェクトの配列として返却します。
70       * @param types インスタンスを取得したいクラスの配列
71       * @return 引数で指定されたクラスに対応するオブジェクト。
72       */
73      public Object[] resolve(Class<?>[] types)
74              throws ContainerException {
75          Object[] rv = new Object[types.length];
76  
77          for (int i = 0; i < types.length; i++) {
78              Class<?> d = types[i];
79              rv[i] = resolve(d);
80          }
81          return rv;
82      }
83  
84      /**
85       * 依存関係のスタックの一番上にあるコンポーネント定義情報を返します。
86       */
87      public final ComponentMetadata peek() {
88          return resolvingComponents.peek();
89      }
90  
91      abstract ComponentMetadata findComponentMetadata(Class<?> role);
92  
93      private String getDependencyPathStr(Stack<ComponentMetadata> path) {
94          StringBuffer sb = new StringBuffer();
95          sb.append(path.get(0).describe());
96          for (int i = 1; i < path.size(); i++) {
97              sb.append(" -> ");
98              sb.append(path.get(i).describe());
99          }
100         return sb.toString();
101     }
102 
103 }