View Javadoc

1   /*
2    * Copyright 2004-2008 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.routing.impl;
17  
18  import java.io.File;
19  import java.io.FilenameFilter;
20  import java.net.URL;
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.Map;
24  import java.util.jar.JarFile;
25  
26  import org.seasar.framework.convention.NamingConvention;
27  import org.seasar.framework.util.ClassLoaderUtil;
28  import org.seasar.framework.util.ClassTraversal;
29  import org.seasar.framework.util.JarFileUtil;
30  import org.seasar.framework.util.ResourceUtil;
31  import org.seasar.framework.util.StringUtil;
32  import org.seasar.framework.util.URLUtil;
33  import org.seasar.framework.util.ZipFileUtil;
34  import org.seasar.framework.util.ClassTraversal.ClassHandler;
35  
36  /**
37   * クラスを抽出するクラスです。
38   * 
39   * @author baba
40   * @since 1.0.0
41   */
42  abstract class ClassCollector implements ClassHandler {
43  
44  	private final Map<String, Strategy> strategies = new HashMap<String, Strategy>();
45  
46  	private final NamingConvention namingConvention;
47  
48  	/**
49  	 * {@link ClassCollector}を作成します。
50  	 * 
51  	 * @param namingConvention
52  	 *            命名規約
53  	 */
54  	protected ClassCollector(final NamingConvention namingConvention) {
55  		this.namingConvention = namingConvention;
56  		addStrategy("file", new FileSystemStrategy());
57  		addStrategy("jar", new JarFileStrategy());
58  		addStrategy("zip", new ZipFileStrategy());
59  		addStrategy("code-source", new CodeSourceFileStrategy());
60  	}
61  
62  	/**
63  	 * 登録されているストラテジを返します。
64  	 * 
65  	 * @return 登録されているストラテジ
66  	 */
67  	public Map<String, Strategy> getStrategies() {
68  		return strategies;
69  	}
70  
71  	/**
72  	 * {@link Strategy} を返します。
73  	 * 
74  	 * @param protocol
75  	 * @return {@link Strategy}
76  	 */
77  	protected Strategy getStrategy(final String protocol) {
78  		return strategies.get(URLUtil.toCanonicalProtocol(protocol));
79  	}
80  
81  	/**
82  	 * {@link Strategy}を追加します。
83  	 * 
84  	 * @param protocol
85  	 * @param strategy
86  	 */
87  	protected void addStrategy(final String protocol, final Strategy strategy) {
88  		strategies.put(protocol, strategy);
89  	}
90  
91  	/**
92  	 * 自動登録を行います。
93  	 */
94  	public void collect() {
95  		final String[] rootPackageNames = namingConvention
96  				.getRootPackageNames();
97  		if (rootPackageNames != null) {
98  			for (int i = 0; i < rootPackageNames.length; ++i) {
99  				final String rootDir = rootPackageNames[i].replace('.', '/');
100 				for (final Iterator<?> it = ClassLoaderUtil
101 						.getResources(rootDir); it.hasNext();) {
102 					final URL url = (URL) it.next();
103 					final Strategy strategy = getStrategy(URLUtil
104 							.toCanonicalProtocol(url.getProtocol()));
105 					strategy.collect(rootDir, url);
106 				}
107 			}
108 			webSphereClassLoaderFix();
109 		}
110 	}
111 
112 	/**
113 	 * Jarファイルからコンポーネントの登録を行います。
114 	 * <p>
115 	 * WebSphere のクラスローダーはJarファイル中のディレクトリエントリを<code>ClassLoader#getResource()</code>で
116 	 * 返してくれないので、 S2のJarと同じ場所にあるJarファイルからコンポーネントの登録を行います。
117 	 * </p>
118 	 */
119 	protected void webSphereClassLoaderFix() {
120 		final URL url = ResourceUtil.getResourceNoException(getClass()
121 				.getName().replace('.', '/')
122 				+ ".class");
123 		if ("wsjar".equals(url.getProtocol())) {
124 			final File s2JarFile = new File(JarFileUtil.toJarFile(url)
125 					.getName());
126 			final File libDir = s2JarFile.getParentFile();
127 			final File[] jarFiles = libDir.listFiles(new FilenameFilter() {
128 				public boolean accept(File dir, String name) {
129 					return name.endsWith(".jar");
130 				}
131 			});
132 			for (int i = 0; i < jarFiles.length; ++i) {
133 				final JarFile jarFile = JarFileUtil.create(jarFiles[i]);
134 				ClassTraversal.forEach(jarFile, this);
135 			}
136 		}
137 	}
138 
139 	/**
140 	 * プロトコルに応じた自動登録を行なうストラテジです。
141 	 * 
142 	 */
143 	protected interface Strategy {
144 		/**
145 		 * 自動登録を行います。
146 		 * 
147 		 * @param path
148 		 *            パス
149 		 * @param url
150 		 *            URL
151 		 */
152 		void collect(String path, URL url);
153 	}
154 
155 	/**
156 	 * ファイルシステム用の {@link Strategy}です。
157 	 */
158 	protected class FileSystemStrategy implements Strategy {
159 
160 		/**
161 		 * {@inheritDoc}
162 		 */
163 		public void collect(String path, URL url) {
164 			File rootDir = getRootDir(path, url);
165 			String[] rootPackageNames = namingConvention.getRootPackageNames();
166 			for (int i = 0; i < rootPackageNames.length; ++i) {
167 				ClassTraversal.forEach(rootDir, rootPackageNames[i],
168 						ClassCollector.this);
169 			}
170 		}
171 
172 		protected File getRootDir(String path, URL url) {
173 			File file = URLUtil.toFile(url);
174 			String[] names = StringUtil.split(path, "/");
175 			for (int i = 0; i < names.length; ++i) {
176 				file = file.getParentFile();
177 			}
178 			return file;
179 		}
180 	}
181 
182 	/**
183 	 * jarファイル用の {@link Strategy}です。
184 	 */
185 	protected class JarFileStrategy implements Strategy {
186 
187 		/**
188 		 * {@inheritDoc}
189 		 */
190 		public void collect(final String path, final URL url) {
191 			final JarFile jarFile = createJarFile(url);
192 			ClassTraversal.forEach(jarFile, ClassCollector.this);
193 		}
194 
195 		/**
196 		 * {@link JarFile}を作成します。
197 		 * 
198 		 * @param url
199 		 * @return {@link JarFile}
200 		 */
201 		protected JarFile createJarFile(final URL url) {
202 			return JarFileUtil.toJarFile(url);
203 		}
204 	}
205 
206 	/**
207 	 * WebLogic固有の<code>zip:</code>プロトコルで表現されるURLをサポートするストラテジです。
208 	 */
209 	protected class ZipFileStrategy implements Strategy {
210 
211 		/**
212 		 * {@inheritDoc}
213 		 */
214 		public void collect(final String path, final URL url) {
215 			final JarFile jarFile = createJarFile(url);
216 			ClassTraversal.forEach(jarFile, ClassCollector.this);
217 		}
218 
219 		/**
220 		 * {@link JarFile}を作成します。
221 		 * 
222 		 * @param url
223 		 * @return {@link JarFile}
224 		 */
225 		protected JarFile createJarFile(final URL url) {
226 			final String jarFileName = ZipFileUtil.toZipFilePath(url);
227 			return JarFileUtil.create(new File(jarFileName));
228 		}
229 	}
230 
231 	/**
232 	 * OC4J固有の<code>code-source:</code>プロトコルで表現されるURLをサポートするストラテジです。
233 	 */
234 	protected class CodeSourceFileStrategy implements Strategy {
235 
236 		/**
237 		 * {@inheritDoc}
238 		 */
239 		public void collect(final String path, final URL url) {
240 			final JarFile jarFile = createJarFile(url);
241 			ClassTraversal.forEach(jarFile, ClassCollector.this);
242 		}
243 
244 		/**
245 		 * {@link JarFile}を作成します。
246 		 * 
247 		 * @param url
248 		 * @return {@link JarFile}
249 		 */
250 		protected JarFile createJarFile(final URL url) {
251 			final URL jarUrl = URLUtil.create("jar:file:" + url.getPath());
252 			return JarFileUtil.toJarFile(jarUrl);
253 		}
254 	}
255 }