Statistics
| Revision:

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
}