svn-gvsig-desktop / tags / v1_1_Build_1014 / libraries / libDriverManager / src / com / hardcode / driverManager / DriverClassLoader.java @ 13593
History | View | Annotate | Download (10.6 KB)
1 | 467 | fernando | package com.hardcode.driverManager; |
---|---|---|---|
2 | |||
3 | import java.io.DataInputStream; |
||
4 | import java.io.File; |
||
5 | import java.io.IOException; |
||
6 | import java.io.InputStream; |
||
7 | |||
8 | import java.net.MalformedURLException; |
||
9 | import java.net.URL; |
||
10 | import java.net.URLClassLoader; |
||
11 | |||
12 | import java.security.AllPermission; |
||
13 | import java.security.CodeSource; |
||
14 | import java.security.PermissionCollection; |
||
15 | import java.security.Permissions; |
||
16 | |||
17 | import java.util.ArrayList; |
||
18 | import java.util.Enumeration; |
||
19 | import java.util.Hashtable; |
||
20 | import java.util.List; |
||
21 | import java.util.StringTokenizer; |
||
22 | import java.util.Vector; |
||
23 | import java.util.jar.JarException; |
||
24 | import java.util.zip.ZipEntry; |
||
25 | import java.util.zip.ZipFile; |
||
26 | |||
27 | |||
28 | /**
|
||
29 | * Class loader que carga las clases pedidas por los plugins de manera que
|
||
30 | * primero busca en el classpath, luego busca en el directorio del propio
|
||
31 | * plugin en los jars especificados por el xml y en caso de no encontrar la
|
||
32 | * clase pide al PluginClassLoaderManager la lista de plugins que pueden
|
||
33 | * satisfacer la clase e intenta cargarlo con cada un de ellos hasta que lo
|
||
34 | * consigue con uno.
|
||
35 | *
|
||
36 | * @author Fernando Gonz?lez Cort?s
|
||
37 | */
|
||
38 | public class DriverClassLoader extends URLClassLoader { |
||
39 | private Hashtable clasesJar = new Hashtable(); |
||
40 | private String baseDir; |
||
41 | |||
42 | /**
|
||
43 | * Creates a new PluginClassLoader object.
|
||
44 | *
|
||
45 | * @param jars Array con la ruta de los jars en los que buscar? las clases
|
||
46 | * el plugin
|
||
47 | * @param baseDir Directorio base del plugin que se carga. Es en directorio
|
||
48 | * donde se buscan los resources en el m?todo getResources
|
||
49 | * @param cl ClassLoader padre del classLoader, al que se le pedir?
|
||
50 | * resolver las clases antes de utilizar el algoritmo propio
|
||
51 | *
|
||
52 | * @throws IOException Si no se puede leer alguno de los jars
|
||
53 | * @throws IllegalArgumentException Si no se especifica un array de jars
|
||
54 | * @throws JarException Si hay dos clases con el mismo nombre en el plugin
|
||
55 | */
|
||
56 | public DriverClassLoader(URL[] jars, String baseDir, ClassLoader cl) |
||
57 | throws IOException { |
||
58 | super(jars, cl);
|
||
59 | this.baseDir = baseDir;
|
||
60 | |||
61 | if (jars == null) { |
||
62 | throw new IllegalArgumentException("jars cannot be null"); //$NON-NLS-1$ |
||
63 | } |
||
64 | |||
65 | //Se itera por las URLS que deben de ser jar's
|
||
66 | ZipFile[] jarFiles = new ZipFile[jars.length]; |
||
67 | |||
68 | for (int i = 0; i < jars.length; i++) { |
||
69 | jarFiles[i] = new ZipFile(jars[i].getPath()); |
||
70 | |||
71 | Enumeration entradas = jarFiles[i].entries();
|
||
72 | |||
73 | //Se itera por todos los .class del jar
|
||
74 | while (entradas.hasMoreElements()) {
|
||
75 | //Se obtiene la entrada
|
||
76 | ZipEntry file = (ZipEntry) entradas.nextElement(); |
||
77 | String fileName = file.getName();
|
||
78 | |||
79 | //Se obtiene el nombre de la clase
|
||
80 | if (!fileName.toLowerCase().endsWith(".class")) { //$NON-NLS-1$ |
||
81 | |||
82 | continue;
|
||
83 | } |
||
84 | |||
85 | fileName = fileName.substring(0, fileName.length() - 6).replace('/', |
||
86 | '.');
|
||
87 | |||
88 | //Se cromprueba si ya hab?a una clase con dicho nombre
|
||
89 | if (clasesJar.get(fileName) != null) { |
||
90 | throw new JarException( |
||
91 | "two or more classes with the same name in the jars: " +
|
||
92 | fileName); |
||
93 | } |
||
94 | |||
95 | //Se registra la clase
|
||
96 | clasesJar.put(fileName, jarFiles[i]); |
||
97 | DriverClassLoaderManager.registerClass(fileName, this);
|
||
98 | } |
||
99 | } |
||
100 | } |
||
101 | |||
102 | /**
|
||
103 | * Carga la clase
|
||
104 | *
|
||
105 | * @param name Nombre de la clase
|
||
106 | * @param resolve SI se ha de resolver la clase o no
|
||
107 | *
|
||
108 | * @return Clase cargada
|
||
109 | *
|
||
110 | * @throws ClassNotFoundException Si no se pudo encontrar la clase
|
||
111 | */
|
||
112 | protected Class loadClass(String name, boolean resolve) |
||
113 | throws ClassNotFoundException { |
||
114 | Class c = null; |
||
115 | |||
116 | try {
|
||
117 | c = super.loadClass(name, resolve);
|
||
118 | } catch (ClassNotFoundException e1) { |
||
119 | if (c == null) { |
||
120 | // Convert class name argument to filename
|
||
121 | // Convert package names into subdirectories
|
||
122 | try {
|
||
123 | ZipFile jar = (ZipFile) clasesJar.get(name); |
||
124 | |||
125 | if (jar == null) { |
||
126 | Vector cls = (Vector) DriverClassLoaderManager.getClassLoaderList(name); |
||
127 | |||
128 | if (cls != null) { |
||
129 | for (int i = 0; i < cls.size(); i++) { |
||
130 | c = ((DriverClassLoader) cls.elementAt(i)).loadClass(name, |
||
131 | resolve); |
||
132 | |||
133 | if (c != null) { |
||
134 | break;
|
||
135 | } |
||
136 | } |
||
137 | } |
||
138 | } else {
|
||
139 | String fileName = name.replace('.', '/') + ".class"; //$NON-NLS-1$ |
||
140 | ZipEntry classFile = jar.getEntry(fileName);
|
||
141 | byte[] data = loadClassData(classFile, |
||
142 | jar.getInputStream(classFile)); |
||
143 | |||
144 | c = defineClass(name, data, 0, data.length);
|
||
145 | } |
||
146 | |||
147 | if (c == null) { |
||
148 | throw new ClassNotFoundException(name); |
||
149 | } |
||
150 | } catch (IOException e) { |
||
151 | throw new ClassNotFoundException("Error_reading_file" + |
||
152 | name); //$NON-NLS-1$
|
||
153 | } |
||
154 | } |
||
155 | } |
||
156 | |||
157 | if (resolve) {
|
||
158 | resolveClass(c); |
||
159 | } |
||
160 | |||
161 | return c;
|
||
162 | } |
||
163 | |||
164 | /**
|
||
165 | * obtiene el array de bytes de la clase
|
||
166 | *
|
||
167 | * @param classFile Entrada dentro del jar contiene los bytecodes de la
|
||
168 | * clase (el .class)
|
||
169 | * @param is InputStream para leer la entrada del jar
|
||
170 | *
|
||
171 | * @return Bytes de la clase
|
||
172 | *
|
||
173 | * @throws IOException Si no se puede obtener el .class del jar
|
||
174 | */
|
||
175 | private byte[] loadClassData(ZipEntry classFile, InputStream is) |
||
176 | throws IOException { |
||
177 | // Get size of class file
|
||
178 | int size = (int) classFile.getSize(); |
||
179 | |||
180 | // Reserve space to read
|
||
181 | byte[] buff = new byte[size]; |
||
182 | |||
183 | // Get stream to read from
|
||
184 | DataInputStream dis = new DataInputStream(is); |
||
185 | |||
186 | // Read in data
|
||
187 | dis.readFully(buff); |
||
188 | |||
189 | // close stream
|
||
190 | dis.close(); |
||
191 | |||
192 | // return data
|
||
193 | return buff;
|
||
194 | } |
||
195 | |||
196 | /**
|
||
197 | * Obtiene los recursos tomando como la raiz el directorio base del plugin.
|
||
198 | * Si no se encuentra el recurso ah? se invoca a getResource del
|
||
199 | * classloader padre, que buscar? en el jar de la aplicaci?n. Si ah?
|
||
200 | * tampoco se encuentra nada se devolver? null.
|
||
201 | *
|
||
202 | * @param res Nombre del recurso
|
||
203 | *
|
||
204 | * @return URL del recurso o null si no se pudo encontrar
|
||
205 | */
|
||
206 | public URL getResource(String res) { |
||
207 | File dir = new File(baseDir); |
||
208 | |||
209 | try {
|
||
210 | ArrayList resource = new ArrayList(); |
||
211 | StringTokenizer st = new StringTokenizer(res, "\\/"); |
||
212 | |||
213 | while (st.hasMoreTokens()) {
|
||
214 | String token = st.nextToken();
|
||
215 | resource.add(token); |
||
216 | } |
||
217 | |||
218 | URL ret = getResource(dir, resource);
|
||
219 | |||
220 | if (ret != null) { |
||
221 | return ret;
|
||
222 | } |
||
223 | } catch (Exception e) { |
||
224 | e.printStackTrace(); |
||
225 | } |
||
226 | |||
227 | return super.getResource(res); |
||
228 | } |
||
229 | |||
230 | /**
|
||
231 | * Busca recursivamente el recurso res en el directorio base. res es una
|
||
232 | * lista de String's con los directorios del path y base es el directorio
|
||
233 | * a partir del cual se busca dicho recurso. En cada ejecuci?n del m?todo
|
||
234 | * se toma el primer elemento de res y se busca dicho directorio en el
|
||
235 | * directorio base. Si se encuentra, ser? el directorio base para una
|
||
236 | * nueva llamada.
|
||
237 | *
|
||
238 | * @param base Directorio desde donde parte la b?squeda del recurso.
|
||
239 | * @param res Lista de strings con el path del recurso que se quiere
|
||
240 | * encontrar
|
||
241 | *
|
||
242 | * @return URL con el recurso
|
||
243 | */
|
||
244 | private URL getResource(File base, List res) { |
||
245 | File[] files = base.listFiles(); |
||
246 | |||
247 | String parte = (String) res.get(0); |
||
248 | |||
249 | for (int i = 0; i < files.length; i++) { |
||
250 | if (files[i].getName().compareTo(parte) == 0) { |
||
251 | if (res.size() == 1) { |
||
252 | try {
|
||
253 | return new URL("file:" + files[i].toString()); |
||
254 | } catch (MalformedURLException e) { |
||
255 | return null; |
||
256 | } |
||
257 | } else {
|
||
258 | return getResource(files[i], res.subList(1, res.size())); |
||
259 | } |
||
260 | } |
||
261 | } |
||
262 | |||
263 | return null; |
||
264 | } |
||
265 | |||
266 | /**
|
||
267 | * Devuelve el nombre del directorio del plugin
|
||
268 | *
|
||
269 | * @return
|
||
270 | */
|
||
271 | public String getPluginName() { |
||
272 | String ret = baseDir.substring(baseDir.lastIndexOf(File.separatorChar) + |
||
273 | 1);
|
||
274 | |||
275 | return ret;
|
||
276 | } |
||
277 | |||
278 | /**
|
||
279 | * @see java.security.SecureClassLoader#getPermissions(java.security.CodeSource)
|
||
280 | */
|
||
281 | protected PermissionCollection getPermissions(CodeSource codesource) { |
||
282 | Permissions perms = new Permissions(); |
||
283 | perms.add(new AllPermission()); |
||
284 | |||
285 | return (perms);
|
||
286 | } |
||
287 | |||
288 | /**
|
||
289 | * Devuelve una instancia de cada driver encontrado en los jars del
|
||
290 | * classloader
|
||
291 | *
|
||
292 | * @return array de drivers
|
||
293 | *
|
||
294 | * @throws ClassNotFoundException if the class cannot be located by the
|
||
295 | * specified class loader
|
||
296 | */
|
||
297 | 658 | fernando | public Class[] getDrivers() throws ClassNotFoundException{ |
298 | 467 | fernando | ArrayList drivers = new ArrayList(); |
299 | Enumeration e = clasesJar.keys();
|
||
300 | |||
301 | while (e.hasMoreElements()) {
|
||
302 | String fileName = (String) e.nextElement(); |
||
303 | |||
304 | if (fileName.endsWith("Driver")) { |
||
305 | Class driver = (Class) this.loadClass(fileName); |
||
306 | drivers.add(driver); |
||
307 | } |
||
308 | } |
||
309 | |||
310 | return (Class[]) drivers.toArray(new Class[0]); |
||
311 | } |
||
312 | 4138 | caballero | /**
|
313 | * Devuelve una instancia de cada writer encontrado en los jars del
|
||
314 | * classloader
|
||
315 | *
|
||
316 | * @return array de drivers
|
||
317 | *
|
||
318 | * @throws ClassNotFoundException if the class cannot be located by the
|
||
319 | * specified class loader
|
||
320 | */
|
||
321 | public Class[] getWriters() throws ClassNotFoundException{ |
||
322 | ArrayList writers = new ArrayList(); |
||
323 | Enumeration e = clasesJar.keys();
|
||
324 | |||
325 | while (e.hasMoreElements()) {
|
||
326 | String fileName = (String) e.nextElement(); |
||
327 | |||
328 | if (fileName.endsWith("Writer")) { |
||
329 | Class driver = (Class) this.loadClass(fileName); |
||
330 | writers.add(driver); |
||
331 | } |
||
332 | } |
||
333 | |||
334 | return (Class[]) writers.toArray(new Class[0]); |
||
335 | } |
||
336 | 467 | fernando | } |