org.openrdf.repository.object.composition.ClassFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alibaba-composition-object Show documentation
Show all versions of alibaba-composition-object Show documentation
The Object Composition library merges multiple Java objects into a single multi-subject object.
/*
* 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;
}
}
private 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);
}
}