Statistics
| Revision:

svn-gvsig-desktop / tags / v1_1_Build_1013 / libraries / libDriverManager / src / com / hardcode / driverManager / DriverClassLoader.java @ 13521

History | View | Annotate | Download (10.6 KB)

1
package com.hardcode.driverManager;
2

    
3
import java.io.DataInputStream;
4
import java.io.File;
5
import java.io.IOException;
6
import java.io.InputStream;
7

    
8
import java.net.MalformedURLException;
9
import java.net.URL;
10
import java.net.URLClassLoader;
11

    
12
import java.security.AllPermission;
13
import java.security.CodeSource;
14
import java.security.PermissionCollection;
15
import java.security.Permissions;
16

    
17
import java.util.ArrayList;
18
import java.util.Enumeration;
19
import java.util.Hashtable;
20
import java.util.List;
21
import java.util.StringTokenizer;
22
import java.util.Vector;
23
import java.util.jar.JarException;
24
import java.util.zip.ZipEntry;
25
import java.util.zip.ZipFile;
26

    
27

    
28
/**
29
 * Class loader que carga las clases pedidas por los plugins de manera que
30
 * primero busca en el classpath, luego busca en el directorio del propio
31
 * plugin en los jars especificados por el xml y en caso de no encontrar la
32
 * clase pide al PluginClassLoaderManager la lista de plugins que pueden
33
 * satisfacer la clase e intenta cargarlo con cada un de ellos hasta que lo
34
 * consigue con uno.
35
 *
36
 * @author Fernando Gonz?lez Cort?s
37
 */
38
public class DriverClassLoader extends URLClassLoader {
39
    private Hashtable clasesJar = new Hashtable();
40
    private String baseDir;
41

    
42
    /**
43
     * Creates a new PluginClassLoader object.
44
     *
45
     * @param jars Array con la ruta de los jars en los que buscar? las clases
46
     *        el plugin
47
     * @param baseDir Directorio base del plugin que se carga. Es en directorio
48
     *        donde se buscan los resources en el m?todo getResources
49
     * @param cl ClassLoader padre del classLoader, al que se le pedir?
50
     *        resolver las clases antes de utilizar el algoritmo propio
51
     *
52
     * @throws IOException Si no se puede leer alguno de los jars
53
     * @throws IllegalArgumentException Si no se especifica un array de jars
54
     * @throws JarException Si hay dos clases con el mismo nombre en el plugin
55
     */
56
    public DriverClassLoader(URL[] jars, String baseDir, ClassLoader cl)
57
        throws IOException {
58
        super(jars, cl);
59
        this.baseDir = baseDir;
60

    
61
        if (jars == null) {
62
            throw new IllegalArgumentException("jars cannot be null"); //$NON-NLS-1$
63
        }
64

    
65
        //Se itera por las URLS que deben de ser jar's
66
        ZipFile[] jarFiles = new ZipFile[jars.length];
67

    
68
        for (int i = 0; i < jars.length; i++) {
69
            jarFiles[i] = new ZipFile(jars[i].getPath());
70

    
71
            Enumeration entradas = jarFiles[i].entries();
72

    
73
            //Se itera por todos los .class del jar
74
            while (entradas.hasMoreElements()) {
75
                //Se obtiene la entrada
76
                ZipEntry file = (ZipEntry) entradas.nextElement();
77
                String fileName = file.getName();
78

    
79
                //Se obtiene el nombre de la clase
80
                if (!fileName.toLowerCase().endsWith(".class")) { //$NON-NLS-1$
81

    
82
                    continue;
83
                }
84

    
85
                fileName = fileName.substring(0, fileName.length() - 6).replace('/',
86
                        '.');
87

    
88
                //Se cromprueba si ya hab?a una clase con dicho nombre
89
                if (clasesJar.get(fileName) != null) {
90
                    throw new JarException(
91
                        "two or more classes with the same name in the jars: " +
92
                        fileName);
93
                }
94

    
95
                //Se registra la clase
96
                clasesJar.put(fileName, jarFiles[i]);
97
                DriverClassLoaderManager.registerClass(fileName, this);
98
            }
99
        }
100
    }
101

    
102
    /**
103
     * Carga la clase
104
     *
105
     * @param name Nombre de la clase
106
     * @param resolve SI se ha de resolver la clase o no
107
     *
108
     * @return Clase cargada
109
     *
110
     * @throws ClassNotFoundException Si no se pudo encontrar la clase
111
     */
112
    protected Class loadClass(String name, boolean resolve)
113
        throws ClassNotFoundException {
114
            Class c = null;
115

    
116
        try {
117
            c = super.loadClass(name, resolve);
118
        } catch (ClassNotFoundException e1) {
119
            if (c == null) {
120
                // Convert class name argument to filename
121
                // Convert package names into subdirectories
122
                try {
123
                    ZipFile jar = (ZipFile) clasesJar.get(name);
124

    
125
                    if (jar == null) {
126
                        Vector cls = (Vector) DriverClassLoaderManager.getClassLoaderList(name);
127

    
128
                        if (cls != null) {
129
                            for (int i = 0; i < cls.size(); i++) {
130
                                c = ((DriverClassLoader) cls.elementAt(i)).loadClass(name,
131
                                        resolve);
132

    
133
                                if (c != null) {
134
                                    break;
135
                                }
136
                            }
137
                        }
138
                    } else {
139
                        String fileName = name.replace('.', '/') + ".class"; //$NON-NLS-1$
140
                        ZipEntry classFile = jar.getEntry(fileName);
141
                        byte[] data = loadClassData(classFile,
142
                                jar.getInputStream(classFile));
143

    
144
                        c = defineClass(name, data, 0, data.length);
145
                    }
146

    
147
                    if (c == null) {
148
                        throw new ClassNotFoundException(name);
149
                    }
150
                } catch (IOException e) {
151
                    throw new ClassNotFoundException("Error_reading_file" +
152
                        name); //$NON-NLS-1$
153
                }
154
            }
155
        }
156

    
157
        if (resolve) {
158
            resolveClass(c);
159
        }
160

    
161
        return c;
162
    }
163

    
164
    /**
165
     * obtiene el array de bytes de la clase
166
     *
167
     * @param classFile Entrada dentro del jar contiene los bytecodes de la
168
     *        clase (el .class)
169
     * @param is InputStream para leer la entrada del jar
170
     *
171
     * @return Bytes de la clase
172
     *
173
     * @throws IOException Si no se puede obtener el .class del jar
174
     */
175
    private byte[] loadClassData(ZipEntry classFile, InputStream is)
176
        throws IOException {
177
        // Get size of class file
178
        int size = (int) classFile.getSize();
179

    
180
        // Reserve space to read
181
        byte[] buff = new byte[size];
182

    
183
        // Get stream to read from
184
        DataInputStream dis = new DataInputStream(is);
185

    
186
        // Read in data
187
        dis.readFully(buff);
188

    
189
        // close stream
190
        dis.close();
191

    
192
        // return data
193
        return buff;
194
    }
195

    
196
    /**
197
     * Obtiene los recursos tomando como la raiz el directorio base del plugin.
198
     * Si no se encuentra el recurso ah? se invoca a getResource del
199
     * classloader padre, que buscar? en el jar de la aplicaci?n. Si ah?
200
     * tampoco se encuentra nada se devolver? null.
201
     *
202
     * @param res Nombre del recurso
203
     *
204
     * @return URL del recurso o null si no se pudo encontrar
205
     */
206
    public URL getResource(String res) {
207
        File dir = new File(baseDir);
208

    
209
        try {
210
            ArrayList resource = new ArrayList();
211
            StringTokenizer st = new StringTokenizer(res, "\\/");
212

    
213
            while (st.hasMoreTokens()) {
214
                String token = st.nextToken();
215
                resource.add(token);
216
            }
217

    
218
            URL ret = getResource(dir, resource);
219

    
220
            if (ret != null) {
221
                return ret;
222
            }
223
        } catch (Exception e) {
224
            e.printStackTrace();
225
        }
226

    
227
        return super.getResource(res);
228
    }
229

    
230
    /**
231
     * Busca recursivamente el recurso res en el directorio base. res es una
232
     * lista de String's con los directorios del path y base es el directorio
233
     * a partir del cual se busca dicho recurso. En cada ejecuci?n del m?todo
234
     * se toma el primer elemento de res y se busca dicho directorio en el
235
     * directorio base. Si se encuentra, ser? el directorio base para una
236
     * nueva llamada.
237
     *
238
     * @param base Directorio desde donde parte la b?squeda del recurso.
239
     * @param res Lista de strings con el path del recurso que se quiere
240
     *        encontrar
241
     *
242
     * @return URL con el recurso
243
     */
244
    private URL getResource(File base, List res) {
245
        File[] files = base.listFiles();
246

    
247
        String parte = (String) res.get(0);
248

    
249
        for (int i = 0; i < files.length; i++) {
250
            if (files[i].getName().compareTo(parte) == 0) {
251
                if (res.size() == 1) {
252
                    try {
253
                        return new URL("file:" + files[i].toString());
254
                    } catch (MalformedURLException e) {
255
                        return null;
256
                    }
257
                } else {
258
                    return getResource(files[i], res.subList(1, res.size()));
259
                }
260
            }
261
        }
262

    
263
        return null;
264
    }
265

    
266
    /**
267
     * Devuelve el nombre del directorio del plugin
268
     *
269
     * @return
270
     */
271
    public String getPluginName() {
272
        String ret = baseDir.substring(baseDir.lastIndexOf(File.separatorChar) +
273
                1);
274

    
275
        return ret;
276
    }
277

    
278
    /**
279
     * @see java.security.SecureClassLoader#getPermissions(java.security.CodeSource)
280
     */
281
    protected PermissionCollection getPermissions(CodeSource codesource) {
282
        Permissions perms = new Permissions();
283
        perms.add(new AllPermission());
284

    
285
        return (perms);
286
    }
287

    
288
    /**
289
     * Devuelve una instancia de cada driver encontrado en los jars del
290
     * classloader
291
     *
292
     * @return array de drivers
293
     *
294
     * @throws ClassNotFoundException if the class cannot be located by the
295
     *         specified class loader
296
     */
297
    public Class[] getDrivers() throws ClassNotFoundException{
298
        ArrayList drivers = new ArrayList();
299
        Enumeration e = clasesJar.keys();
300

    
301
        while (e.hasMoreElements()) {
302
            String fileName = (String) e.nextElement();
303

    
304
            if (fileName.endsWith("Driver")) {
305
                Class driver = (Class) this.loadClass(fileName);
306
                drivers.add(driver);
307
            }
308
        }
309

    
310
        return (Class[]) drivers.toArray(new Class[0]);
311
    }
312
    /**
313
     * Devuelve una instancia de cada writer encontrado en los jars del
314
     * classloader
315
     *
316
     * @return array de drivers
317
     *
318
     * @throws ClassNotFoundException if the class cannot be located by the
319
     *         specified class loader
320
     */
321
    public Class[] getWriters() throws ClassNotFoundException{
322
        ArrayList writers = new ArrayList();
323
        Enumeration e = clasesJar.keys();
324

    
325
        while (e.hasMoreElements()) {
326
            String fileName = (String) e.nextElement();
327

    
328
            if (fileName.endsWith("Writer")) {
329
                Class driver = (Class) this.loadClass(fileName);
330
                writers.add(driver);
331
            }
332
        }
333

    
334
        return (Class[]) writers.toArray(new Class[0]);
335
    }
336
}