All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openrdf.repository.object.composition.ClassFactory Maven / Gradle / Ivy

Go to download

The Object Composition library merges multiple Java objects into a single multi-subject object.

The newest version!
/*
 * Copyright (c) 2009, James Leigh All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * - Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution. 
 * - Neither the name of the openrdf.org nor the names of its contributors may
 *   be used to endorse or promote products derived from this software without
 *   specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 */
package org.openrdf.repository.object.composition;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.LoaderClassPath;
import javassist.NotFoundException;
import javassist.bytecode.Descriptor;

import org.openrdf.repository.object.exceptions.ObjectCompositionException;

/**
 * Factory class for creating Class and ClassTemplates.
 * 
 * @author James Leigh
 *
 */
public class ClassFactory extends ClassLoader {

	public static Class classForName(String name, ClassLoader cl)
			throws ClassNotFoundException {
		if (cl == null)
			return Class.forName(name);
		synchronized (cl) {
			return Class.forName(name, true, cl);
		}
	}

	private Reference cp;
	private File output;
	private List alternatives = new ArrayList();

	/**
	 * Creates a new Class Factory using the current context class loader.
	 */
	public ClassFactory(File dir) {
		this(dir, Thread.currentThread().getContextClassLoader());
	}

	/**
	 * Create a given Class Factory with the given class loader.
	 * 
	 * @param parent
	 */
	public ClassFactory(File dir, ClassLoader parent) {
		super(parent);
		this.output = dir;
		dir.mkdirs();
	}

	public synchronized Class classForName(String name)
			throws ClassNotFoundException {
		return Class.forName(name, true, this);
	}

	public synchronized Object newInstance(String name) throws ClassNotFoundException,
			InstantiationException, IllegalAccessException {
		return classForName(name).newInstance();
	}

	/**
	 * Create the new Java Class from this template.
	 * 
	 * @param template
	 * @return new Java Class Object
	 * @throws ObjectCompositionException
	 */
	public Class createClass(ClassTemplate template)
			throws ObjectCompositionException {
		CtClass cc = template.getCtClass();
		String name = cc.getName();
		try {
			byte[] bytecode = cc.toBytecode();
			cc.detach();
			return defineClass(name, bytecode);
		} catch (IOException e) {
			throw new ObjectCompositionException(e);
		} catch (CannotCompileException e) {
			throw new ObjectCompositionException(e);
		}
	}

	/**
	 * Create a new Class template, which can later be used to create a Java
	 * class.
	 * 
	 * @param className
	 * @return temporary Class template
	 */
	public ClassTemplate createClassTemplate(String className) {
		ClassPool cp = getClassPool();
		return new ClassTemplate(cp.makeClass(className), this);
	}

	public ClassTemplate loadClassTemplate(Class class1) {
		return new ClassTemplate(get(class1), this);
	}

	/**
	 * Create a new Class template, which can later be used to create a Java
	 * class.
	 * 
	 * @param name
	 * @param class1
	 *            super class
	 * @return temporary Class template
	 */
	public ClassTemplate createClassTemplate(String name, Class class1) {
		ClassPool cp = getClassPool();
		CtClass cc = cp.makeClass(name, get(class1));
		return new ClassTemplate(cc, this);
	}

	@Override
	public URL getResource(String name) {
		try {
			File file = new File(output, name);
			if (file.exists())
				return file.toURI().toURL();
		} catch (MalformedURLException e) {
			throw new AssertionError(e);
		}
		URL url = super.getResource(name);
		if (url != null)
			return url;
		synchronized (alternatives) {
			for (ClassLoader cl : alternatives) {
				url = cl.getResource(name);
				if (url != null)
					return url;
			}
		}
		return null;
	}

	@Override
	public InputStream getResourceAsStream(String name) {
		File file = new File(output, name);
		if (file.exists()) {
			try {
				return new FileInputStream(file);
			} catch (FileNotFoundException e) {
			}
		}
		InputStream stream = getParent().getResourceAsStream(name);
		if (stream != null)
			return stream;
		synchronized (alternatives) {
			for (ClassLoader cl : alternatives) {
				stream = cl.getResourceAsStream(name);
				if (stream != null)
					return stream;
			}
		}
		return null;
	}

	@Override
	public Enumeration getResources(String name) throws IOException {
		Enumeration resources = super.getResources(name);
		if (resources.hasMoreElements())
			return resources;
		synchronized (alternatives) {
			for (ClassLoader cl : alternatives) {
				resources = cl.getResources(name);
				if (resources.hasMoreElements())
					return resources;
			}
		}
		return resources;
	}

	@Override
	protected Class findClass(String name) throws ClassNotFoundException {
		try {
			return super.findClass(name);
		} catch (ClassNotFoundException e) {
			synchronized (alternatives) {
				for (ClassLoader cl : alternatives) {
					try {
						return cl.loadClass(name);
					} catch (ClassNotFoundException e1) {
						continue;
					}
				}
			}
			throw e;
		}
	}

	public void appendClassLoader(ClassLoader cl) {
		synchronized (alternatives) {
			alternatives.add(cl);
		}
	}

	CtClass get(Class type) throws ObjectCompositionException {
		ClassPool cp = getClassPool();
		if (type.isPrimitive()) {
			return getPrimitive(type);
		}
		try {
			if (type.isArray())
				return Descriptor.toCtClass(type.getName(), cp);
			return cp.get(type.getName());
		} catch (NotFoundException e) {
			try {
				ClassLoader cl = type.getClassLoader();
				if (cl == null)
					throw new ObjectCompositionException(e);
				appendClassLoader(cl);
				if (type.isArray())
					return Descriptor.toCtClass(type.getName(), cp);
				return cp.get(type.getName());
			} catch (NotFoundException e1) {
				throw new ObjectCompositionException(e);
			}
		}
	}

	private CtClass getPrimitive(Class type) {
		if (type.equals(Boolean.TYPE))
			return CtClass.booleanType;
		if (type.equals(Byte.TYPE))
			return CtClass.byteType;
		if (type.equals(Character.TYPE))
			return CtClass.charType;
		if (type.equals(Double.TYPE))
			return CtClass.doubleType;
		if (type.equals(Float.TYPE))
			return CtClass.floatType;
		if (type.equals(Integer.TYPE))
			return CtClass.intType;
		if (type.equals(Long.TYPE))
			return CtClass.longType;
		if (type.equals(Short.TYPE))
			return CtClass.shortType;
		if (type.equals(Void.TYPE))
			return CtClass.voidType;
		throw new ObjectCompositionException("Unknown primative type: "
				+ type.getName());
	}

	private synchronized ClassPool getClassPool() {
		ClassPool pool = cp == null ? null : cp.get();
		if (pool == null) {
			pool = new ClassPool();
			pool.appendClassPath(new LoaderClassPath(this));
			cp = new SoftReference(pool);
		}
		return pool;
	}

	private Class defineClass(String name, byte[] bytecode) {
		String resource = name.replace('.', '/') + ".class";
		saveResource(resource, bytecode);
		return defineClass(name, bytecode, 0, bytecode.length);
	}

	private void saveResource(String fileName, byte[] bytecode) {
		try {
			File file = new File(output, fileName);
			file.getParentFile().mkdirs();
			FileOutputStream out = new FileOutputStream(file);
			try {
				out.write(bytecode);
			} finally {
				out.close();
			}
		} catch (IOException e) {
			throw new AssertionError(e);
		}
	}

	Class getJavaClass(CtClass cc) throws ClassNotFoundException {
		if (cc.isPrimitive()) {
			if (cc.equals(CtClass.booleanType))
				return Boolean.TYPE;
			if (cc.equals(CtClass.byteType))
				return Byte.TYPE;
			if (cc.equals(CtClass.charType))
				return Character.TYPE;
			if (cc.equals(CtClass.doubleType))
				return Double.TYPE;
			if (cc.equals(CtClass.floatType))
				return Float.TYPE;
			if (cc.equals(CtClass.intType))
				return Integer.TYPE;
			if (cc.equals(CtClass.longType))
				return Long.TYPE;
			if (cc.equals(CtClass.shortType))
				return Short.TYPE;
			throw new AssertionError();
		}
		String name = Descriptor.toJavaName(Descriptor.toJvmName(cc));
		return classForName(name);
	}

	/**
	 * @return The directory where class files are looked up.
	 */
	public File getOutput() {
		return output;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy