View Javadoc

1   /*
2    * Copyright 2004-2009 the Seasar Foundation and the Others.
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,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.cubby.plugins.s2.spi;
17  
18  import java.lang.reflect.Modifier;
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.seasar.cubby.plugins.s2.detector.ClassDetector;
23  import org.seasar.cubby.plugins.s2.detector.DetectClassProcessor;
24  import org.seasar.cubby.routing.PathResolver;
25  import org.seasar.cubby.spi.PathResolverProvider;
26  import org.seasar.cubby.util.ActionUtils;
27  import org.seasar.framework.convention.NamingConvention;
28  import org.seasar.framework.util.ClassUtil;
29  import org.seasar.framework.util.Disposable;
30  import org.seasar.framework.util.DisposableUtil;
31  
32  /**
33   * S2Container 向けの {@link PathResolver} のプロバイダです。
34   * <p>
35   * クラスパスを走査しアクションクラスを登録します。
36   * </p>
37   * 
38   * @author baba
39   */
40  public class S2PathResolverProvider implements PathResolverProvider,
41  		DetectClassProcessor, Disposable {
42  
43  	public static final String pathResolver_BINDING = "bindingType=must";
44  
45  	public static final String namingConvention_BINDING = "bindingType=must";
46  
47  	public static final String classDetector_BINDING = "bindingType=must";
48  
49  	/** パスに対応するアクションメソッドを解決するためのクラス。 */
50  	private PathResolver pathResolver;
51  
52  	/** 命名規約。 */
53  	private NamingConvention namingConvention;
54  
55  	/** クラスパスを走査してクラスを検出するクラス。 */
56  	public ClassDetector classDetector;
57  
58  	/** インスタンスが初期化済みであることを示します。 */
59  	private boolean initialized;
60  
61  	/** アクションクラスのリスト。 */
62  	private final List<Class<?>> actionClasses = new ArrayList<Class<?>>();
63  
64  	/**
65  	 * パスに対応するアクションメソッドを解決するためのクラスを設定します。
66  	 * 
67  	 * @param pathResolver
68  	 *            パスに対応するアクションメソッドを解決するためのクラス
69  	 * 
70  	 */
71  	public void setPathResolver(final PathResolver pathResolver) {
72  		this.pathResolver = pathResolver;
73  	}
74  
75  	/**
76  	 * クラスパスを走査してクラスを検出するクラスを設定します。
77  	 * 
78  	 * @param classDetector
79  	 *            クラスパスを走査してクラスを検出するクラス
80  	 */
81  	public void setClassDetector(final ClassDetector classDetector) {
82  		this.classDetector = classDetector;
83  	}
84  
85  	/**
86  	 * 命名規約を設定します。
87  	 * 
88  	 * @param namingConvention
89  	 *            命名規約
90  	 */
91  	public void setNamingConvention(final NamingConvention namingConvention) {
92  		this.namingConvention = namingConvention;
93  	}
94  
95  	/**
96  	 * 初期化します。
97  	 */
98  	public void initialize() {
99  		synchronized (pathResolver) {
100 			if (initialized) {
101 				return;
102 			}
103 			classDetector.detect();
104 			pathResolver.addAll(actionClasses);
105 
106 			DisposableUtil.add(this);
107 			initialized = true;
108 		}
109 	}
110 
111 	/**
112 	 * {@inheritDoc}
113 	 */
114 	public void dispose() {
115 		actionClasses.clear();
116 		pathResolver.clear();
117 		initialized = false;
118 	}
119 
120 	/**
121 	 * {@inheritDoc}
122 	 * <p>
123 	 * 指定されたパッケージ名、クラス名から導出されるクラスがアクションクラスだった場合はルーティングを登録します。
124 	 * </p>
125 	 */
126 	public void processClass(final String packageName,
127 			final String shortClassName) {
128 		if (shortClassName.indexOf('$') != -1) {
129 			return;
130 		}
131 		final String className = ClassUtil.concatName(packageName,
132 				shortClassName);
133 		if (!namingConvention.isTargetClassName(className)) {
134 			return;
135 		}
136 		if (!className.endsWith(namingConvention.getActionSuffix())) {
137 			return;
138 		}
139 		final Class<?> clazz = ClassUtil.forName(className);
140 		if (namingConvention.isSkipClass(clazz)) {
141 			return;
142 		}
143 		if (Modifier.isAbstract(clazz.getModifiers())) {
144 			return;
145 		}
146 		if (!ActionUtils.isActionClass(clazz)) {
147 			return;
148 		}
149 		actionClasses.add(clazz);
150 	}
151 
152 	/**
153 	 * {@inheritDoc}
154 	 */
155 	public PathResolver getPathResolver() {
156 		initialize();
157 		return pathResolver;
158 	}
159 
160 }