View Javadoc

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