Statistics
| Revision:

svn-gvsig-desktop / branches / org.gvsig.desktop-2018a / org.gvsig.desktop.framework / org.gvsig.andami / src / main / java / org / gvsig / andami / plugins / PluginClassLoader.java @ 43888

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