/*******************************************************************************
* Copyright (c) 1998, 2008 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.sdo.helper;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.Method;
import org.eclipse.persistence.sdo.SDOConstants;
import org.eclipse.persistence.sdo.SDODataObject;
import org.eclipse.persistence.sdo.SDOType;
import org.eclipse.persistence.internal.libraries.asm.ClassWriter;
import org.eclipse.persistence.internal.libraries.asm.CodeVisitor;
import org.eclipse.persistence.internal.libraries.asm.Constants;
import org.eclipse.persistence.internal.libraries.asm.Type;
import commonj.sdo.helper.HelperContext;
/**
* <p><b>Purpose</b>: Dynamically create a class for the given name as a subclass of the generic
* superclass. This dynamically created subclass should only provide constructors
* and a writeReplace() method.
*/
public class DynamicClassWriter {
private Class parentClass;
private String className;
private SDOType type;
// hold the context containing all helpers so that we can preserve inter-helper relationships
private HelperContext aHelperContext;
public DynamicClassWriter(String className, SDOType type, HelperContext aContext) {
aHelperContext = aContext;
this.parentClass = SDODataObject.class;
this.className = className;
this.type = type;
initializeParentClass();
}
private void initializeParentClass() {
if (type.isSubType()) {
SDOType parentSDOType = (SDOType)type.getBaseTypes().get(0);
String parentClassName = parentSDOType.getInstanceClassName() + SDOConstants.SDO_IMPL_NAME;
try {
parentClass = ((SDOXMLHelper)aHelperContext.getXMLHelper()).getLoader().loadClass(parentClassName, parentSDOType);
} catch (Exception e) {
parentClass = null;
}
if (parentClass == null) {
parentClass = SDODataObject.class;
}
} else {
parentClass = SDODataObject.class;
}
}
public Class getParentClass() {
return this.parentClass;
}
public String getClassName() {
return this.className;
}
/**
* This is where the byte codes for the generic subclass are defined and the
* class is created dynamically from them.
*/
public byte[] createClass() {
ClassWriter cw = new ClassWriter(false);
cw.visit(Constants.V1_5, Constants.ACC_PUBLIC + Constants.ACC_SUPER, className.replace('.', '/'), Type.getType(parentClass).getInternalName(), null, null);
addConstructors(cw);
addWriteReplace(cw);
cw.visitEnd();
return cw.toByteArray();
}
private void addConstructors(ClassWriter cw) {
CodeVisitor mv = cw.visitMethod(Constants.ACC_PUBLIC, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[0]), new String[] { Type.getInternalName(Serializable.class) }, null);
mv.visitVarInsn(Constants.ALOAD, 0);
mv.visitMethodInsn(Constants.INVOKESPECIAL, Type.getType(parentClass).getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[0]));
mv.visitInsn(Constants.RETURN);
mv.visitMaxs(1, 1);
}
private void addWriteReplace(ClassWriter cw) {
Method method;
try {
method = parentClass.getDeclaredMethod("writeReplace", new Class[0]);
} catch (NoSuchMethodException e) {
return;
}
CodeVisitor mv = cw.visitMethod(Constants.ACC_PROTECTED, method.getName(), Type.getMethodDescriptor(method), new String[] { Type.getInternalName(ObjectStreamException.class) }, null);
mv.visitVarInsn(Constants.ALOAD, 0);
mv.visitMethodInsn(Constants.INVOKESPECIAL, Type.getInternalName(parentClass), method.getName(), Type.getMethodDescriptor(method));
mv.visitInsn(Constants.ARETURN);
mv.visitMaxs(1, 1);
}
}