svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.framework / org.gvsig.andami / src / main / java / org / gvsig / andami / plugins / PluginClassLoader.java @ 47436
History | View | Annotate | Download (24.7 KB)
1 | 40559 | jjdelcerro | /**
|
---|---|---|---|
2 | * gvSIG. Desktop Geographic Information System.
|
||
3 | 40435 | jjdelcerro | *
|
4 | 40559 | jjdelcerro | * Copyright (C) 2007-2013 gvSIG Association.
|
5 | 40435 | jjdelcerro | *
|
6 | 42437 | jjdelcerro | * This program is free software; you can redistribute it and/or modify it under
|
7 | * the terms of the GNU General Public License as published by the Free Software
|
||
8 | * Foundation; either version 3 of the License, or (at your option) any later
|
||
9 | * version.
|
||
10 | 40435 | jjdelcerro | *
|
11 | 42437 | jjdelcerro | * This program is distributed in the hope that it will be useful, but WITHOUT
|
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||
13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||
14 | * details.
|
||
15 | 40435 | jjdelcerro | *
|
16 | 42437 | jjdelcerro | * You should have received a copy of the GNU General Public License along with
|
17 | * this program; if not, write to the Free Software Foundation, Inc., 51
|
||
18 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
19 | 40435 | jjdelcerro | *
|
20 | 42437 | jjdelcerro | * For any additional information, do not hesitate to contact us at info AT
|
21 | * gvsig.com, or visit our website www.gvsig.com.
|
||
22 | 40435 | jjdelcerro | */
|
23 | package org.gvsig.andami.plugins; |
||
24 | |||
25 | 47436 | fdiaz | import java.io.Console; |
26 | 40435 | jjdelcerro | import java.io.DataInputStream; |
27 | import java.io.File; |
||
28 | import java.io.FileInputStream; |
||
29 | import java.io.IOException; |
||
30 | import java.io.InputStream; |
||
31 | import java.net.MalformedURLException; |
||
32 | import java.net.URL; |
||
33 | import java.net.URLClassLoader; |
||
34 | import java.security.AllPermission; |
||
35 | import java.security.CodeSource; |
||
36 | import java.security.PermissionCollection; |
||
37 | import java.util.ArrayList; |
||
38 | 41231 | jjdelcerro | import java.util.Arrays; |
39 | 42774 | jbadia | import java.util.Collections; |
40 | 40435 | jjdelcerro | import java.util.Enumeration; |
41 | 42559 | jjdelcerro | import java.util.HashMap; |
42 | 41770 | fdiaz | import java.util.HashSet; |
43 | 40435 | jjdelcerro | import java.util.Hashtable; |
44 | 40566 | jjdelcerro | import java.util.Iterator; |
45 | 40435 | jjdelcerro | import java.util.List; |
46 | 40566 | jjdelcerro | import java.util.Map; |
47 | import java.util.Map.Entry; |
||
48 | 41770 | fdiaz | import java.util.Set; |
49 | 40435 | jjdelcerro | import java.util.StringTokenizer; |
50 | import java.util.zip.ZipEntry; |
||
51 | import java.util.zip.ZipException; |
||
52 | import java.util.zip.ZipFile; |
||
53 | 43853 | jjdelcerro | import org.apache.commons.lang3.StringUtils; |
54 | 40435 | jjdelcerro | |
55 | 40566 | jjdelcerro | import org.gvsig.andami.messages.Messages; |
56 | 47436 | fdiaz | import org.gvsig.tools.future.FutureUtils; |
57 | 40435 | jjdelcerro | import org.slf4j.Logger; |
58 | import org.slf4j.LoggerFactory; |
||
59 | |||
60 | /**
|
||
61 | 42437 | jjdelcerro | * <p>
|
62 | * Class loader which loads the classes requested by the plugins. It first tries
|
||
63 | * to search in the classpath, then it requests the class to the parent
|
||
64 | * classloader, then it searches in the owns plugins' library dir, and if all
|
||
65 | * these methods fail, it tries to load the class from any of the depended
|
||
66 | * plugins. Finally, if this also fails, the other classloaders provided in the
|
||
67 | * <code>addLoaders</code> method are requested to load the class.</p>
|
||
68 | 40435 | jjdelcerro | *
|
69 | 42437 | jjdelcerro | * <p>
|
70 | * The class loader can also be used to load resources from the plugin's
|
||
71 | * directory by using the <code>getResource()</code> method.</p>
|
||
72 | *
|
||
73 | 40435 | jjdelcerro | * @author Fernando Gonz�lez Cort�s
|
74 | */
|
||
75 | public class PluginClassLoader extends URLClassLoader { |
||
76 | 42437 | jjdelcerro | |
77 | /**
|
||
78 | * DOCUMENT ME!
|
||
79 | */
|
||
80 | 40599 | jjdelcerro | private static Logger logger = LoggerFactory.getLogger(PluginClassLoader.class.getName()); |
81 | 40435 | jjdelcerro | |
82 | |||
83 | 42559 | jjdelcerro | private Map<String, ZipFile> clasesJar = new HashMap<>(); |
84 | |||
85 | |||
86 | 40435 | jjdelcerro | private File baseDir; |
87 | 41231 | jjdelcerro | private List<PluginClassLoader> pluginLoaders; |
88 | 42559 | jjdelcerro | private static List<ClassLoader> otherLoaders = new ArrayList<>(); |
89 | 42437 | jjdelcerro | private boolean isOtherLoader = false; |
90 | |||
91 | 40435 | jjdelcerro | /**
|
92 | * Creates a new PluginClassLoader object.
|
||
93 | *
|
||
94 | * @param jars Array with the search paths where classes will be searched
|
||
95 | * @param baseDir Base directory for this plugin. This is the directory
|
||
96 | * which will be used as basedir in the <code>getResources</code> method.
|
||
97 | * @param cl The parent classloader of this classloader. It will be used to
|
||
98 | * search classes before trying to search in the plugin's directory
|
||
99 | * @param pluginLoaders The classloaders of the depended plugins.
|
||
100 | *
|
||
101 | * @throws IOException
|
||
102 | */
|
||
103 | public PluginClassLoader(URL[] jars, String baseDir, ClassLoader cl, |
||
104 | 42437 | jjdelcerro | PluginClassLoader[] pluginLoaders) throws IOException { |
105 | 41231 | jjdelcerro | this(jars, baseDir, cl, Arrays.asList(pluginLoaders)); |
106 | 41025 | jjdelcerro | } |
107 | 42437 | jjdelcerro | |
108 | 41025 | jjdelcerro | public PluginClassLoader(URL[] jars, String baseDir, ClassLoader cl, |
109 | 41231 | jjdelcerro | List<PluginClassLoader> pluginLoaders) throws IOException { |
110 | 40435 | jjdelcerro | super(jars, cl);
|
111 | this.baseDir = new File(new File(baseDir).getAbsolutePath()); |
||
112 | 42559 | jjdelcerro | try {
|
113 | logger.debug("Creating PluginClassLoader for {}.", this.getPluginName()); |
||
114 | this.pluginLoaders = new ArrayList(); |
||
115 | this.pluginLoaders.addAll(pluginLoaders);
|
||
116 | 40435 | jjdelcerro | |
117 | 42559 | jjdelcerro | if (jars == null || jars.length < 1) { |
118 | debugDump(); |
||
119 | return;
|
||
120 | } |
||
121 | ZipFile[] jarFiles = new ZipFile[jars.length]; |
||
122 | 40435 | jjdelcerro | |
123 | 42559 | jjdelcerro | for (int i = 0; i < jars.length; i++) { |
124 | try {
|
||
125 | logger.debug("Classloader {}, loading jar {}", this.getPluginName(), jars[i].getPath()); |
||
126 | jarFiles[i] = new ZipFile(jars[i].getPath()); |
||
127 | 40435 | jjdelcerro | |
128 | 42559 | jjdelcerro | Enumeration<? extends ZipEntry> entradas = jarFiles[i].entries(); |
129 | 40435 | jjdelcerro | |
130 | 42559 | jjdelcerro | while (entradas.hasMoreElements()) {
|
131 | ZipEntry file = (ZipEntry) entradas.nextElement(); |
||
132 | String fileName = file.getName();
|
||
133 | 40435 | jjdelcerro | |
134 | 42559 | jjdelcerro | if (!fileName.toLowerCase().endsWith(".class")) { //$NON-NLS-1$ |
135 | 40435 | jjdelcerro | |
136 | 42559 | jjdelcerro | continue;
|
137 | } |
||
138 | 40435 | jjdelcerro | |
139 | 42559 | jjdelcerro | fileName = fileName.substring(0, fileName.length() - 6) |
140 | .replace('/', '.'); |
||
141 | 40435 | jjdelcerro | |
142 | 42559 | jjdelcerro | if (clasesJar.get(fileName) != null) { |
143 | logger.warn("Classloader {}, duplicated class {} in {} and {}",
|
||
144 | new Object[]{ |
||
145 | this.getPluginName(),
|
||
146 | fileName, |
||
147 | jarFiles[i].getName(), |
||
148 | clasesJar.get(fileName).getName() |
||
149 | } |
||
150 | ); |
||
151 | } else {
|
||
152 | clasesJar.put(fileName, jarFiles[i]); |
||
153 | } |
||
154 | 40435 | jjdelcerro | } |
155 | 42559 | jjdelcerro | } catch (ZipException e) { |
156 | throw new IOException(e.getMessage() + " Jar: " |
||
157 | + jars[i].getPath() + ": " + jarFiles[i]);
|
||
158 | } catch (IOException e) { |
||
159 | throw e;
|
||
160 | 40435 | jjdelcerro | } |
161 | } |
||
162 | 42559 | jjdelcerro | } finally {
|
163 | debugDump(); |
||
164 | 40435 | jjdelcerro | } |
165 | } |
||
166 | |||
167 | 40566 | jjdelcerro | private void debugDump() { |
168 | 42437 | jjdelcerro | if (!logger.isDebugEnabled()) {
|
169 | return;
|
||
170 | } |
||
171 | logger.debug(this.toString());
|
||
172 | logger.debug(" baseDir: " + this.baseDir); |
||
173 | logger.debug(" parent: " + this.getParent()); |
||
174 | logger.debug(" depends:");
|
||
175 | 42559 | jjdelcerro | for (PluginClassLoader pluginLoader : this.pluginLoaders) { |
176 | logger.debug(" {}", pluginLoader.toString());
|
||
177 | 42437 | jjdelcerro | } |
178 | logger.debug(" urls:");
|
||
179 | URL[] urls = this.getURLs(); |
||
180 | 42559 | jjdelcerro | for (URL url : urls) { |
181 | logger.debug(" " + url.toString());
|
||
182 | 42437 | jjdelcerro | } |
183 | 42559 | jjdelcerro | // logger.debug(" classes:");
|
184 | // Iterator<Map.Entry<String, ZipFile>> it = this.clasesJar.entrySet().iterator();
|
||
185 | // while (it.hasNext()) {
|
||
186 | // Entry<String, ZipFile> entry = it.next();
|
||
187 | // logger.debug(" " + entry.getKey() + "(" + entry.getValue().getName() + ")");
|
||
188 | // }
|
||
189 | 40566 | jjdelcerro | } |
190 | 42437 | jjdelcerro | |
191 | 40435 | jjdelcerro | protected Class singleLoadClass(String name) throws ClassNotFoundException { |
192 | 41788 | jjdelcerro | Class<?> c;
|
193 | 42559 | jjdelcerro | Set<String> pluginsVisiteds = new HashSet<>(); |
194 | 41788 | jjdelcerro | c = this.singleLoadClass(pluginsVisiteds, name);
|
195 | return c;
|
||
196 | 40435 | jjdelcerro | } |
197 | |||
198 | /**
|
||
199 | * Carga la clase
|
||
200 | *
|
||
201 | * @param name Nombre de la clase
|
||
202 | * @param resolve Si se ha de resolver la clase o no
|
||
203 | *
|
||
204 | * @return Clase cargada
|
||
205 | *
|
||
206 | * @throws ClassNotFoundException Si no se pudo encontrar la clase
|
||
207 | */
|
||
208 | 42559 | jjdelcerro | @Override
|
209 | 40435 | jjdelcerro | protected Class loadClass(String name, boolean resolve) |
210 | 42437 | jjdelcerro | throws ClassNotFoundException { |
211 | 40566 | jjdelcerro | Class<?> c = null; |
212 | 40435 | jjdelcerro | |
213 | 47429 | fdiaz | if(StringUtils.equals(name, "java.nio.file.SimpleFileVisitor")){ |
214 | 47408 | fdiaz | logger.info("Loading SimpleFileVisitor: isOtherLoader = "+isOtherLoader+" PluginName = "+this.getPluginName()); |
215 | } |
||
216 | 42559 | jjdelcerro | // Intentamos cargar con el URLClassLoader
|
217 | 43853 | jjdelcerro | for( int retry=0; c==null && retry<3; retry++) { |
218 | try {
|
||
219 | if (!isOtherLoader) {
|
||
220 | c = super.loadClass(name, resolve);
|
||
221 | logger.debug("Classloader {}, found class {}.", this.getPluginName(), name); |
||
222 | } |
||
223 | } catch (ClassNotFoundException e1) { |
||
224 | 47429 | fdiaz | if(StringUtils.equals(name, "java.nio.file.SimpleFileVisitor")){ |
225 | 47408 | fdiaz | logger.info("ClassNotFoundException SimpleFileVisitor in classLoader = "+super.getClass().getName(),e1); |
226 | } |
||
227 | 42437 | jjdelcerro | } |
228 | 43853 | jjdelcerro | if (c == null) { |
229 | 42437 | jjdelcerro | try {
|
230 | 43853 | jjdelcerro | c = singleLoadClass(name); |
231 | } catch (ClassNotFoundException e2) { |
||
232 | } |
||
233 | } |
||
234 | if (c == null) { |
||
235 | try {
|
||
236 | 42437 | jjdelcerro | isOtherLoader = true;
|
237 | c = loadOtherClass(name); |
||
238 | } catch (ClassNotFoundException e3) { |
||
239 | 47436 | fdiaz | if(StringUtils.equals(name, "java.nio.file.SimpleFileVisitor")){ |
240 | logger.info("Crash loading SimpleFileVisitor: isOtherLoader = "+isOtherLoader+" PluginName = "+this.getPluginName()); |
||
241 | if(FutureUtils.use("ClassLoaderDebug")){ |
||
242 | logger.info("Pulse enter to continue");
|
||
243 | Console console = System.console();
|
||
244 | console.readLine(); |
||
245 | } |
||
246 | } |
||
247 | 40435 | jjdelcerro | throw new ClassNotFoundException("Class " + name |
248 | 42437 | jjdelcerro | + " not found through the plugin " + baseDir, e3);
|
249 | } finally {
|
||
250 | isOtherLoader = false;
|
||
251 | } |
||
252 | } |
||
253 | 43853 | jjdelcerro | if( c==null ) { |
254 | logger.info("class "+name+", retry "+retry); |
||
255 | } |
||
256 | 40435 | jjdelcerro | } |
257 | 42437 | jjdelcerro | if (c == null) { |
258 | 43853 | jjdelcerro | if( StringUtils.startsWith(name,"java.") || StringUtils.startsWith(name,"javax.") ) { |
259 | logger.warn("Can't locate class '"+name+"'. It can be a serious problem. It is advisable that you close the application."); |
||
260 | } |
||
261 | 42437 | jjdelcerro | throw new ClassNotFoundException(Messages.getString( |
262 | "PluginClassLoader.Error_reading_file") + name);
|
||
263 | } |
||
264 | 40435 | jjdelcerro | if (resolve) {
|
265 | resolveClass(c); |
||
266 | } |
||
267 | return c;
|
||
268 | } |
||
269 | 42437 | jjdelcerro | |
270 | 40566 | jjdelcerro | private Class<?> loadOtherClass(String name) |
271 | 41231 | jjdelcerro | throws ClassNotFoundException { |
272 | 42559 | jjdelcerro | ClassLoader[] ocls = (ClassLoader[]) otherLoaders.toArray(new ClassLoader[0]); |
273 | Class<?> c;
|
||
274 | for (ClassLoader ocl : ocls) { |
||
275 | c = ocl.loadClass(name); |
||
276 | 41231 | jjdelcerro | if (c != null) { |
277 | 42559 | jjdelcerro | logger.debug("Classloader {}, found class {} in classloader {}",
|
278 | new Object[]{this, getPluginName(), name, ocl.toString()} |
||
279 | ); |
||
280 | 41231 | jjdelcerro | return c;
|
281 | } |
||
282 | } |
||
283 | throw new ClassNotFoundException(name); |
||
284 | 40435 | jjdelcerro | } |
285 | |||
286 | /**
|
||
287 | * obtiene el array de bytes de la clase
|
||
288 | *
|
||
289 | * @param classFile Entrada dentro del jar contiene los bytecodes de la
|
||
290 | 42437 | jjdelcerro | * clase (el .class)
|
291 | 40435 | jjdelcerro | * @param is InputStream para leer la entrada del jar
|
292 | *
|
||
293 | * @return Bytes de la clase
|
||
294 | *
|
||
295 | * @throws IOException Si no se puede obtener el .class del jar
|
||
296 | */
|
||
297 | private byte[] loadClassData(ZipEntry classFile, InputStream is) |
||
298 | 42437 | jjdelcerro | throws IOException { |
299 | 40435 | jjdelcerro | // Get size of class file
|
300 | int size = (int) classFile.getSize(); |
||
301 | |||
302 | // Reserve space to read
|
||
303 | byte[] buff = new byte[size]; |
||
304 | |||
305 | // Get stream to read from
|
||
306 | DataInputStream dis = new DataInputStream(is); |
||
307 | |||
308 | // Read in data
|
||
309 | dis.readFully(buff); |
||
310 | |||
311 | // close stream
|
||
312 | dis.close(); |
||
313 | |||
314 | // return data
|
||
315 | return buff;
|
||
316 | } |
||
317 | |||
318 | /**
|
||
319 | * Gets the bytes of a File
|
||
320 | *
|
||
321 | * @param file File
|
||
322 | *
|
||
323 | * @return bytes of file
|
||
324 | *
|
||
325 | * @throws IOException If the operation fails
|
||
326 | */
|
||
327 | private byte[] loadClassData(File file) throws IOException { |
||
328 | InputStream is = new FileInputStream(file); |
||
329 | |||
330 | // Get the size of the file
|
||
331 | long length = file.length();
|
||
332 | |||
333 | // You cannot create an array using a long type.
|
||
334 | // It needs to be an int type.
|
||
335 | // Before converting to an int type, check
|
||
336 | // to ensure that file is not larger than Integer.MAX_VALUE.
|
||
337 | if (length > Integer.MAX_VALUE) { |
||
338 | // File is too large
|
||
339 | } |
||
340 | |||
341 | // Create the byte array to hold the data
|
||
342 | byte[] bytes = new byte[(int) length]; |
||
343 | |||
344 | // Read in the bytes
|
||
345 | int offset = 0; |
||
346 | int numRead = 0; |
||
347 | |||
348 | 42437 | jjdelcerro | while ((offset < bytes.length)
|
349 | && ((numRead = is.read(bytes, offset, bytes.length - offset)) >= 0)) {
|
||
350 | 40435 | jjdelcerro | offset += numRead; |
351 | } |
||
352 | |||
353 | 40566 | jjdelcerro | // Close the input stream and return bytes
|
354 | is.close(); |
||
355 | |||
356 | 40435 | jjdelcerro | // Ensure all the bytes have been read in
|
357 | if (offset < bytes.length) {
|
||
358 | 42437 | jjdelcerro | throw new IOException("Could not completely read file " |
359 | + file.getName()); |
||
360 | 40435 | jjdelcerro | } |
361 | |||
362 | return bytes;
|
||
363 | } |
||
364 | |||
365 | /**
|
||
366 | * Gets the requested resource. If the path is relative, its base directory
|
||
367 | 42437 | jjdelcerro | * will be the one provided in the PluginClassLoader's constructor. If the
|
368 | * resource is not found, search in dependents plugins, otherwise the parent
|
||
369 | * classloader will be invoked to try to get it. If it is not found, it will
|
||
370 | * return null.
|
||
371 | 40435 | jjdelcerro | *
|
372 | * @param res An absolute or relative path to the requested resource.
|
||
373 | *
|
||
374 | * @return Resource's URL if it was found, nul otherwise.
|
||
375 | */
|
||
376 | 42559 | jjdelcerro | @Override
|
377 | 40435 | jjdelcerro | public URL getResource(String res) { |
378 | 42559 | jjdelcerro | URL ret ;
|
379 | 41770 | fdiaz | |
380 | 42559 | jjdelcerro | Set<String> pluginsVisiteds = new HashSet<>(); |
381 | 41788 | jjdelcerro | ret = this.getResource(pluginsVisiteds, res);
|
382 | 40566 | jjdelcerro | return ret;
|
383 | 40435 | jjdelcerro | } |
384 | |||
385 | /**
|
||
386 | * Gets the requested resource. If the path is relative, its base directory
|
||
387 | 42437 | jjdelcerro | * will be the one provided in the PluginClassLoader's constructor. If the
|
388 | * resource is not found, the parent classloader will be invoked to try to
|
||
389 | * get it. If it is not found, it will return null.
|
||
390 | 40435 | jjdelcerro | *
|
391 | * @param res An absolute or relative path to the requested resource.
|
||
392 | *
|
||
393 | * @return Resource's URL if it was found, nul otherwise.
|
||
394 | */
|
||
395 | 40566 | jjdelcerro | private URL getResource(File base, List<String> res) { |
396 | 40435 | jjdelcerro | File[] files = base.listFiles(); |
397 | |||
398 | 40566 | jjdelcerro | String parte = res.get(0); |
399 | 40435 | jjdelcerro | |
400 | 42559 | jjdelcerro | for (File file : files) { |
401 | if (file.getName().compareTo(parte) == 0) { |
||
402 | 40435 | jjdelcerro | if (res.size() == 1) { |
403 | try {
|
||
404 | 42559 | jjdelcerro | return new URL("file:" + file.toString()); |
405 | }catch (MalformedURLException e) { |
||
406 | 40435 | jjdelcerro | return null; |
407 | } |
||
408 | } else {
|
||
409 | 42559 | jjdelcerro | return getResource(file, res.subList(1, res.size())); |
410 | 40435 | jjdelcerro | } |
411 | } |
||
412 | } |
||
413 | |||
414 | return null; |
||
415 | } |
||
416 | 42774 | jbadia | |
417 | @Override
|
||
418 | public Enumeration<URL> getResources(String name) throws IOException { |
||
419 | 42929 | jjdelcerro | HashSet visitedPlugins = new HashSet(); |
420 | return getResources(name, visitedPlugins);
|
||
421 | } |
||
422 | |||
423 | protected Enumeration<URL> getResources(String name, HashSet<PluginClassLoader> visitedPlugins) throws IOException { |
||
424 | 42774 | jbadia | List<URL> resources = new ArrayList<>(); |
425 | Enumeration<URL> aux = super.getResources(name); |
||
426 | while(aux.hasMoreElements()){
|
||
427 | URL url = aux.nextElement();
|
||
428 | resources.add(url); |
||
429 | } |
||
430 | 42929 | jjdelcerro | visitedPlugins.add(this);
|
431 | 42774 | jbadia | for(PluginClassLoader loader: this.pluginLoaders){ |
432 | 42929 | jjdelcerro | if (!visitedPlugins.contains(loader)) {
|
433 | aux = loader.getResources(name, visitedPlugins); |
||
434 | while(aux.hasMoreElements()){
|
||
435 | URL url = aux.nextElement();
|
||
436 | resources.add(url); |
||
437 | } |
||
438 | } |
||
439 | 42774 | jbadia | } |
440 | return Collections.enumeration(resources); |
||
441 | } |
||
442 | 40435 | jjdelcerro | |
443 | /**
|
||
444 | 42437 | jjdelcerro | * Returns the name of the plugin (the name of the directory containing the
|
445 | * plugin).
|
||
446 | 40435 | jjdelcerro | *
|
447 | * @return An String containing the plugin's name.
|
||
448 | */
|
||
449 | public String getPluginName() { |
||
450 | 42437 | jjdelcerro | return baseDir.getName();
|
451 | 40435 | jjdelcerro | } |
452 | |||
453 | /*
|
||
454 | * @see java.security.SecureClassLoader#getPermissions(java.security.CodeSource)
|
||
455 | */
|
||
456 | 42559 | jjdelcerro | @Override
|
457 | 40435 | jjdelcerro | protected PermissionCollection getPermissions(CodeSource codesource) { |
458 | PermissionCollection perms = super.getPermissions(codesource); |
||
459 | perms.add(new AllPermission()); |
||
460 | |||
461 | return perms;
|
||
462 | } |
||
463 | |||
464 | /**
|
||
465 | 42437 | jjdelcerro | * Gets the plugin's base Iterator<Map.Entry<Integer, Integer>>dir, the
|
466 | * directory which will be used to search resources.
|
||
467 | 40435 | jjdelcerro | *
|
468 | * @return Returns the baseDir.
|
||
469 | */
|
||
470 | public String getBaseDir() { |
||
471 | return baseDir.getAbsolutePath();
|
||
472 | } |
||
473 | |||
474 | /**
|
||
475 | * Adds other classloader to use when all the normal methods fail.
|
||
476 | 42437 | jjdelcerro | *
|
477 | * @param classLoaders An ArrayList of ClassLoaders which will be used to
|
||
478 | * load classes when all the normal methods fail.
|
||
479 | 40435 | jjdelcerro | */
|
480 | 42437 | jjdelcerro | public static void addLoaders(ArrayList classLoaders) { |
481 | otherLoaders.addAll(classLoaders); |
||
482 | } |
||
483 | 40435 | jjdelcerro | |
484 | @Override
|
||
485 | public String toString() { |
||
486 | return super.toString() + " (" + getPluginName() + ")"; |
||
487 | } |
||
488 | 42437 | jjdelcerro | |
489 | 41231 | jjdelcerro | public void addPluginClassLoader(PluginClassLoader pluginClassLoader) { |
490 | 42437 | jjdelcerro | if (!this.pluginLoaders.contains(pluginClassLoader)) { |
491 | 41344 | jjdelcerro | this.pluginLoaders.add(pluginClassLoader);
|
492 | } |
||
493 | 41231 | jjdelcerro | } |
494 | 42437 | jjdelcerro | |
495 | 41788 | jjdelcerro | private Class singleLoadClass(Set<String> pluginsVisiteds, String name) throws ClassNotFoundException { |
496 | 42437 | jjdelcerro | |
497 | if (pluginsVisiteds.contains(this.getPluginName())) { |
||
498 | 41770 | fdiaz | return null; |
499 | } |
||
500 | pluginsVisiteds.add(this.getPluginName());
|
||
501 | |||
502 | 41788 | jjdelcerro | // Buscamos en las clases de las librer�as del plugin
|
503 | Class<?> c = findLoadedClass(name);
|
||
504 | |||
505 | if (c != null) { |
||
506 | return c;
|
||
507 | } |
||
508 | |||
509 | 42559 | jjdelcerro | logger.debug("Classloader {}, searching class '{}'",
|
510 | new Object[]{this.getPluginName(), name} |
||
511 | ); |
||
512 | 41788 | jjdelcerro | try {
|
513 | ZipFile jar = (ZipFile) clasesJar.get(name); |
||
514 | |||
515 | //No esta en ningun jar
|
||
516 | if (jar == null) { |
||
517 | //Buscamos en el directorio de clases
|
||
518 | 42437 | jjdelcerro | String classFileName = baseDir + "/classes/" |
519 | + name.replace('.', '/') + ".class"; |
||
520 | 41788 | jjdelcerro | File f = new File(classFileName); |
521 | 42437 | jjdelcerro | if (f.exists()) {
|
522 | 41788 | jjdelcerro | byte[] data = loadClassData(f); |
523 | c = defineClass(name, data, 0, data.length);
|
||
524 | 42559 | jjdelcerro | logger.debug("Classloader {}/classes-folder, found class {}",
|
525 | new Object[]{this.getPluginName(), name} |
||
526 | ); |
||
527 | 41788 | jjdelcerro | |
528 | } else {
|
||
529 | 42559 | jjdelcerro | for (PluginClassLoader pluginLoader1 : pluginLoaders) {
|
530 | 41788 | jjdelcerro | c = null;
|
531 | 42559 | jjdelcerro | PluginClassLoader pluginLoader = pluginLoader1; |
532 | if (pluginLoader != null) { |
||
533 | 41788 | jjdelcerro | try {
|
534 | 42559 | jjdelcerro | c = pluginLoader.singleLoadClass(pluginsVisiteds, name); |
535 | 41788 | jjdelcerro | } catch (ClassNotFoundException e) { |
536 | // Si no la encontramos en el primer plugin, capturamos la exceptcion
|
||
537 | // porque es probable que la encontremos en el resto de plugins.
|
||
538 | } |
||
539 | 42559 | jjdelcerro | if (c != null) { |
540 | logger.debug("Classloader {}, found class {} in plugin {}",
|
||
541 | new Object[]{ |
||
542 | this.getPluginName(),
|
||
543 | name, |
||
544 | pluginLoader.getPluginName() |
||
545 | } |
||
546 | ); |
||
547 | return c;
|
||
548 | } |
||
549 | 41788 | jjdelcerro | } |
550 | } |
||
551 | 42559 | jjdelcerro | |
552 | |||
553 | 41770 | fdiaz | } |
554 | 41788 | jjdelcerro | } else {
|
555 | 42559 | jjdelcerro | logger.debug("Classloader {}, found class {} in jar {}",
|
556 | new Object[]{ |
||
557 | this.getPluginName(),
|
||
558 | name, |
||
559 | jar.getName() |
||
560 | } |
||
561 | ); |
||
562 | 41788 | jjdelcerro | String fileName = name.replace('.', '/') + ".class"; |
563 | ZipEntry classFile = jar.getEntry(fileName);
|
||
564 | byte[] data = loadClassData(classFile, |
||
565 | jar.getInputStream(classFile)); |
||
566 | |||
567 | c = defineClass(name, data, 0, data.length);
|
||
568 | 42559 | jjdelcerro | if (c == null) { |
569 | logger.debug("Classloader {}, can't load class {} from jar {}",
|
||
570 | new Object[]{ |
||
571 | this.getPluginName(),
|
||
572 | name, |
||
573 | jar.getName() |
||
574 | } |
||
575 | ); |
||
576 | } |
||
577 | 42437 | jjdelcerro | |
578 | 41770 | fdiaz | } |
579 | 41788 | jjdelcerro | |
580 | if (c == null) { |
||
581 | 42559 | jjdelcerro | logger.debug("Classloader {}, class not found {}",
|
582 | new Object[]{ |
||
583 | this.getPluginName(),
|
||
584 | name |
||
585 | } |
||
586 | ); |
||
587 | debugDump(); |
||
588 | 41788 | jjdelcerro | throw new ClassNotFoundException(name); |
589 | 41770 | fdiaz | } |
590 | |||
591 | 41788 | jjdelcerro | return c;
|
592 | } catch (IOException e) { |
||
593 | 42559 | jjdelcerro | logger.debug("Classloader {}, error loading class {}",
|
594 | new Object[]{ |
||
595 | this.getPluginName(),
|
||
596 | name |
||
597 | }, |
||
598 | e |
||
599 | ); |
||
600 | 41788 | jjdelcerro | throw new ClassNotFoundException(Messages.getString( |
601 | "PluginClassLoader.Error_reading_file") + name);
|
||
602 | 42437 | jjdelcerro | } |
603 | 41770 | fdiaz | } |
604 | |||
605 | 41788 | jjdelcerro | /**
|
606 | 42437 | jjdelcerro | * Este metodo busca en este class loader y en el de los plugins de los que
|
607 | * depende. Se cerciora de que no se queda bucleado cuando hay una relacion
|
||
608 | * recursiva entre los plugins.
|
||
609 | *
|
||
610 | * @param pluginsVisiteds, set con los plugins que va visitando para evitar
|
||
611 | * que se quede bucleado cuando hay referencia ciclicas entre plugins.
|
||
612 | 41788 | jjdelcerro | * @param res
|
613 | 42437 | jjdelcerro | *
|
614 | * @return
|
||
615 | 41788 | jjdelcerro | */
|
616 | 42437 | jjdelcerro | private URL getResource(Set<String> pluginsVisiteds, String res) { |
617 | 41770 | fdiaz | URL ret = null; |
618 | |||
619 | 42437 | jjdelcerro | if (pluginsVisiteds.contains(this.getPluginName())) { |
620 | 41770 | fdiaz | return null; |
621 | } |
||
622 | pluginsVisiteds.add(this.getPluginName());
|
||
623 | |||
624 | 41788 | jjdelcerro | //
|
625 | // Primero buscamos en el directorio del plugin.
|
||
626 | try {
|
||
627 | 44903 | jjdelcerro | // if( res.contains("cosa") ) {
|
628 | // logger.info("Classloader {}, searching resource '{}'", this.getPluginName(), res);
|
||
629 | // }
|
||
630 | 42559 | jjdelcerro | logger.debug("Classloader {}, searching resource '{}'", this.getPluginName(), res); |
631 | List<String> resource = new ArrayList<>(); |
||
632 | 41788 | jjdelcerro | StringTokenizer st = new StringTokenizer(res, "\\/"); |
633 | 42437 | jjdelcerro | while (st.hasMoreTokens()) {
|
634 | 41788 | jjdelcerro | String token = st.nextToken();
|
635 | resource.add(token); |
||
636 | } |
||
637 | ret = getResource(baseDir, resource); |
||
638 | 42437 | jjdelcerro | if (ret != null) { |
639 | 41788 | jjdelcerro | return ret;
|
640 | } |
||
641 | } catch (Exception e) { |
||
642 | 42559 | jjdelcerro | logger.warn("Classloader {}, Error getting resource '{}'.",
|
643 | new Object[]{ |
||
644 | this.getPluginName(), res
|
||
645 | }, |
||
646 | e |
||
647 | ); |
||
648 | 41788 | jjdelcerro | } |
649 | |||
650 | 44903 | jjdelcerro | // if( res.contains("cosa") ) {
|
651 | // logger.info("Classloader {}, searching in depends pluginLoaders", this.getPluginName());
|
||
652 | // }
|
||
653 | 42559 | jjdelcerro | logger.debug("Classloader {}, searching in depends pluginLoaders", this.getPluginName()); |
654 | for (PluginClassLoader pluginClassLoader : this.pluginLoaders) { |
||
655 | 42437 | jjdelcerro | if (pluginClassLoader != null) { |
656 | 41770 | fdiaz | try {
|
657 | 41788 | jjdelcerro | ret = pluginClassLoader.getResource(pluginsVisiteds, res); |
658 | 42437 | jjdelcerro | if (ret != null) { |
659 | 42559 | jjdelcerro | logger.debug("Classloader {}, Found resource '{}' in plugin '{}'.",
|
660 | 41770 | fdiaz | new Object[]{ |
661 | 42559 | jjdelcerro | this.getPluginName(), res, pluginClassLoader.getPluginName(),});
|
662 | 41770 | fdiaz | return ret;
|
663 | } |
||
664 | } catch (Exception e) { |
||
665 | // Ignore, try in next classloader
|
||
666 | 44390 | jjdelcerro | } finally {
|
667 | pluginsVisiteds.add(pluginClassLoader.getPluginName()); |
||
668 | 41770 | fdiaz | } |
669 | } |
||
670 | } |
||
671 | 41788 | jjdelcerro | |
672 | 42437 | jjdelcerro | if (ret == null) { |
673 | 41788 | jjdelcerro | //
|
674 | // Por ultimo en el class loader padre, se supone que es el del sistema.
|
||
675 | try {
|
||
676 | ret = super.getResource(res);
|
||
677 | } catch (Exception e) { |
||
678 | 42559 | jjdelcerro | logger.warn("Classloader {}, error getting resource '{}' in parent classloader'",
|
679 | new Object[]{this.getPluginName(), res}, |
||
680 | e |
||
681 | ); |
||
682 | 41788 | jjdelcerro | } |
683 | 42437 | jjdelcerro | if (ret == null) { |
684 | 42559 | jjdelcerro | logger.debug("Classloader {}, Resource '{}' not found.",
|
685 | new Object[]{this.getPluginName(), res} |
||
686 | ); |
||
687 | 41788 | jjdelcerro | } |
688 | } |
||
689 | return ret;
|
||
690 | 41770 | fdiaz | } |
691 | 41788 | jjdelcerro | |
692 | 44171 | jjdelcerro | @Override
|
693 | public void addURL(URL url) { |
||
694 | super.addURL(url);
|
||
695 | } |
||
696 | |||
697 | |||
698 | 40435 | jjdelcerro | } |