source: branches/1.0.x/abcl/src/org/armedbear/lisp/JavaClassLoader.java

Last change on this file was 13369, checked in by Mark Evenson, 14 years ago

Make JAVA:ADD-TO-CLASSPATH a generic function.

With this change we can customize the mechanism for changing the
classpath. The first planned use is for JSS to use an :after method
to be informed of classpath additions, so we can factor out the ASDF
portion into the ABCL-ASDF extension package.

Add JAVA:GET-CURRENT-CLASSLOADER to access a wrapped instance of the
underlying current JVM classloader being used by ABCL.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.8 KB
Line 
1/*
2 * JavaClassLoader.java
3 *
4 * Copyright (C) 2003-2005 Peter Graves
5 * $Id: JavaClassLoader.java 13369 2011-07-01 14:00:27Z mevenson $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import static org.armedbear.lisp.Lisp.*;
37
38import java.util.Collections;
39import java.util.HashSet;
40import java.util.Set;
41import java.net.URL;
42import java.net.URLClassLoader;
43
44public class JavaClassLoader extends URLClassLoader {
45
46    private static JavaClassLoader persistentInstance;
47
48    private static Set<String> packages = Collections.synchronizedSet(new HashSet<String>());
49
50    public JavaClassLoader()
51    {
52        this(JavaClassLoader.class.getClassLoader());
53    }
54
55    public JavaClassLoader(ClassLoader parent) {
56  super(new URL[] {}, parent);
57    }
58
59    public JavaClassLoader(URL[] classpath, ClassLoader parent) {
60  super(classpath, parent);
61    }
62
63    public static JavaClassLoader getPersistentInstance()
64    {
65        return getPersistentInstance(null);
66    }
67
68    public static JavaClassLoader getPersistentInstance(String packageName)
69    {
70        if (persistentInstance == null)
71            persistentInstance = new JavaClassLoader();
72  definePackage(packageName);
73        return persistentInstance;
74    }
75
76    private static void definePackage(String packageName)
77    {
78        if (packageName != null && !packages.contains(packageName)) {
79            persistentInstance.definePackage(packageName,"","1.0","","","1.0","",null);
80            packages.add(packageName);
81        }
82    }
83
84    public Class<?> loadClassFromByteArray(byte[] classbytes) {
85        return loadClassFromByteArray(null, classbytes);
86    }
87
88    public Class<?> loadClassFromByteArray(String className,
89                                                byte[] classbytes)
90    {
91        try {
92            long length = classbytes.length;
93            if (length < Integer.MAX_VALUE) {
94                Class<?> c =
95                    defineClass(className, classbytes, 0, (int) length);
96                if (c != null) {
97                    resolveClass(c);
98                    return c;
99                }
100            }
101        }
102      catch (LinkageError e) {
103                throw e;
104      }
105        catch (Throwable t) {
106            Debug.trace(t);
107        }
108        return null;
109    }
110
111    public Class<?> loadClassFromByteArray(String className, byte[] bytes,
112                                                int offset, int length)
113    {
114        try {
115            Class<?> c = defineClass(className, bytes, offset, length);
116            if (c != null) {
117                resolveClass(c);
118                return c;
119            }
120        }
121        catch (VerifyError e)
122          {
123            error(new LispError("Class verification failed: " + e.getMessage()));
124          }
125        catch (Throwable t) {
126            Debug.trace(t);
127        }
128        return null;
129    }
130
131    @Override
132    public void addURL(URL url) {
133  super.addURL(url);
134    }
135
136    public static final Symbol CLASSLOADER = PACKAGE_JAVA.intern("*CLASSLOADER*");
137
138    private static final Primitive GET_DEFAULT_CLASSLOADER = new pf_get_default_classloader();
139    private static final class pf_get_default_classloader extends Primitive {
140 
141  private final LispObject defaultClassLoader = new JavaObject(new JavaClassLoader());
142
143        pf_get_default_classloader() {
144            super("get-default-classloader", PACKAGE_JAVA, true, "");
145        }
146
147        @Override
148        public LispObject execute() {
149      return defaultClassLoader;
150        }
151    };
152
153    // ### make-classloader &optional parent => java-class-loader
154    private static final Primitive MAKE_CLASSLOADER = new pf_make_classloader();
155    private static final class pf_make_classloader extends Primitive
156    {
157        pf_make_classloader() 
158        {
159            super("make-classloader", PACKAGE_JAVA, true, "&optional parent");
160        }
161
162        @Override
163        public LispObject execute() {
164      return new JavaObject(new JavaClassLoader(getCurrentClassLoader()));
165        }
166
167        @Override
168        public LispObject execute(LispObject parent) {
169      return new JavaObject(new JavaClassLoader((ClassLoader) parent.javaInstance(ClassLoader.class)));
170        }
171    };
172
173    // ### dump-classpath &optional classloader => list-of-pathname-lists
174    private static final Primitive DUMP_CLASSPATH = new pf_dump_classpath();
175    private static final class pf_dump_classpath extends Primitive
176    {
177        pf_dump_classpath() 
178        {
179            super("dump-classpath", PACKAGE_JAVA, true, "&optional classloader");
180        }
181
182        @Override
183        public LispObject execute() {
184      return execute(new JavaObject(getCurrentClassLoader()));
185        }
186
187        @Override
188        public LispObject execute(LispObject classloader) {
189      LispObject list = NIL;
190      Object o = classloader.javaInstance();
191      while(o instanceof ClassLoader) {
192    ClassLoader cl = (ClassLoader) o;
193    list = list.push(dumpClassPath(cl));
194    o = cl.getParent();
195      }
196      return list.nreverse();
197        }
198    };
199
200    private static final Primitive GET_CURRENT_CLASSLOADER = new pf_get_current_classloader();
201    @DocString(name="get-current-classloader")
202    private static final class pf_get_current_classloader extends Primitive {
203        pf_get_current_classloader() {
204            super("get-current-classloader", PACKAGE_JAVA, true);
205        }
206        @Override 
207        public LispObject execute() {
208            return new JavaObject(getCurrentClassLoader());
209        }
210    };
211       
212    // ### %add-to-classpath jar-or-jars &optional (classloader (get-current-classloader))
213    private static final Primitive ADD_TO_CLASSPATH = new pf_add_to_classpath();
214    private static final class pf_add_to_classpath extends Primitive
215    {
216        pf_add_to_classpath() 
217        {
218            super("%add-to-classpath", PACKAGE_JAVA, false, 
219                  "jar-or-jars &optional (classloader (get-current-classloader))");
220        }
221
222        @Override
223        public LispObject execute(LispObject jarOrJars) {
224      return execute(jarOrJars, new JavaObject(getCurrentClassLoader()));
225        }
226
227        @Override
228        public LispObject execute(LispObject jarOrJars, LispObject classloader) {
229      Object o = classloader.javaInstance();
230      if(o instanceof JavaClassLoader) {
231    JavaClassLoader jcl = (JavaClassLoader) o;
232    if(jarOrJars instanceof Cons) {
233        while(jarOrJars != NIL) {
234      addURL(jcl, jarOrJars.car());
235      jarOrJars = jarOrJars.cdr();
236        }
237    } else {
238        addURL(jcl, jarOrJars);
239    }
240    return T;
241      } else {
242    return error(new TypeError(o + " must be an instance of " + JavaClassLoader.class.getName()));
243      }
244        }
245    };
246
247    protected static void addURL(JavaClassLoader jcl, LispObject jar) {
248        if (jar instanceof Pathname) {
249            jcl.addURL(((Pathname) jar).toURL());
250        } else if (jar instanceof AbstractString) {
251            jcl.addURL(new Pathname(jar.toString()).toURL());
252        } else {
253            error(new TypeError(jar + " must be a pathname designator"));
254        }
255    }
256
257
258    public static LispObject dumpClassPath(ClassLoader o) {
259  if(o instanceof URLClassLoader) {
260      LispObject list = NIL;
261      for(URL u : ((URLClassLoader) o).getURLs()) {
262    list = list.push(new Pathname(u));
263      }
264      return new Cons(new JavaObject(o), list.nreverse());
265  } else {
266      return new JavaObject(o);
267  }
268    }
269
270    public static ClassLoader getCurrentClassLoader() {
271  LispObject classLoader = CLASSLOADER.symbolValueNoThrow();
272  if(classLoader != null) {
273      return (ClassLoader) classLoader.javaInstance(ClassLoader.class);
274  } else {
275      return Lisp.class.getClassLoader();
276  }
277    }
278
279
280
281}
Note: See TracBrowser for help on using the repository browser.