001/*
002 * Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved. 
003 * Use is subject to license terms.
004 *
005 * Redistribution and use in source and binary forms, with or without modification, are 
006 * permitted provided that the following conditions are met: Redistributions of source code 
007 * must retain the above copyright notice, this list of conditions and the following disclaimer.
008 * Redistributions in binary form must reproduce the above copyright notice, this list of 
009 * conditions and the following disclaimer in the documentation and/or other materials 
010 * provided with the distribution. Neither the name of the Sun Microsystems nor the names of 
011 * is contributors may be used to endorse or promote products derived from this software 
012 * without specific prior written permission. 
013
014 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
015 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
016 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
017 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
018 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
019 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
020 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
021 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
022 * POSSIBILITY OF SUCH DAMAGE.
023 */
024
025/*
026 * MemoryClassLoader.java
027 * @author A. Sundararajan
028 */
029
030package org.kepler.scriptengine.java;
031
032import java.io.File;
033import java.net.MalformedURLException;
034import java.net.URL;
035import java.net.URLClassLoader;
036import java.util.ArrayList;
037import java.util.List;
038import java.util.Map;
039import java.util.StringTokenizer;
040
041/**
042 * ClassLoader that loads .class bytes from memory.
043 */
044public final class MemoryClassLoader extends URLClassLoader {
045    private Map<String, byte[]> classBytes;
046
047    public MemoryClassLoader(Map<String, byte[]> classBytes, 
048               String classPath, ClassLoader parent) {
049        super(toURLs(classPath), parent);
050        this.classBytes = classBytes; 
051    }
052
053    public MemoryClassLoader(Map<String, byte[]> classBytes, String classPath) {
054        this(classBytes, classPath, null);
055    }
056
057    public Class<?> load(String className) throws ClassNotFoundException {
058        return loadClass(className);
059    }
060
061    public Iterable<Class<?>> loadAll() throws ClassNotFoundException {
062        List<Class<?>> classes = new ArrayList<Class<?>>(classBytes.size());
063        for (String name : classBytes.keySet()) {
064            classes.add(loadClass(name));
065        }
066        return classes;
067    }
068
069    @Override
070    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
071
072        byte[] buf = classBytes.get(name);
073        if (buf != null) {
074            //System.out.println("found defn for " + name);
075            
076            // clear the bytes in map -- we don't need it anymore
077            classBytes.put(name, null);
078            Class<?> clazz = defineClass(name, buf, 0, buf.length);
079            if(resolve) {
080                resolveClass(clazz);
081            }
082            return clazz;
083        }
084        return super.loadClass(name, resolve);
085    }
086
087    /* NOTE: this does not allow us to override existing classes. Instead we
088     * override the loadClass(String, boolean) method.
089     */
090    /*
091    @Override
092        protected Class<?> findClass(String className) throws ClassNotFoundException {
093        byte[] buf = classBytes.get(className);
094        if (buf != null) {
095            // clear the bytes in map -- we don't need it anymore
096            classBytes.put(className, null);
097            return defineClass(className, buf, 0, buf.length);
098        } else {
099            return super.findClass(className);
100        }
101    }
102    */
103
104    private static URL[] toURLs(String classPath) {
105        if (classPath == null) {
106            return new URL[0];
107        }
108
109        List<URL> list = new ArrayList<URL>();
110        StringTokenizer st = new StringTokenizer(classPath, File.pathSeparator);
111        while (st.hasMoreTokens()) {
112            String token = st.nextToken();
113            File file = new File(token);
114            if (file.exists()) {
115                try {
116                    list.add(file.toURI().toURL());
117                } catch (MalformedURLException mue) {}
118            } else {
119                try {
120                    list.add(new URL(token));
121                } catch (MalformedURLException mue) {}
122            }
123        }
124        URL[] res = new URL[list.size()];
125        list.toArray(res);
126        return res;
127    }
128}