View Javadoc

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