/**
* Copyright (C) 2001-2004 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.objectweb.speedo.mapper.lib;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.speedo.api.Debug;
import org.objectweb.speedo.tools.StringReplace;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Constants;
import org.objectweb.asm.CodeVisitor;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
/**
* This class contains primitive to serialize and deserialize an Object into a
* java Stirng.
*
* @author S.Chassande-Barrioz
*/
public abstract class Object2StringSerializer {
public final static String DESC_FILE_NAME_PROP = "descFileName";
/**
* Serializes an object into a String
*
* @param o is the java object to serialize
* @return the java object serialized into a String
* @throws java.io.IOException occurs if the java serialization fails
*/
public static String serialize(Object o) throws IOException {
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
byte[] bs = baos.toByteArray();
baos.close();
StringBuffer sb = new StringBuffer(bs.length);
for (int i = 0; i < bs.length; i++) {
sb.append((char) (bs[i] & 0XFF));
}
return sb.toString();
}
/**
* Deserializes a String into a java object.
*
* @param s is the string containing a serialized java object
* @return the deserialized java object
* @throws IOException occurs if the deserialization fails
* @throws ClassNotFoundException occurs a class of a deserialized java
* object is not present.
*/
public static Object deserialize(String s) throws IOException, ClassNotFoundException {
byte[] bs = new byte[s.length()];
for (int i = 0; i < bs.length; i++) {
bs[i] = (byte) s.charAt(i);
}
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bs));
Object o = ois.readObject();
ois.close();
return o;
}
public static String serialize(String output, String descFileName, Object jmi, Logger logger) throws IOException {
String className = descFileName2ClassName(descFileName);
if (Debug.ON && logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(
BasicLevel.DEBUG,
"Serialize the Jorm Meta Information into the class '"
+ className
+ "' into the directory '"
+ output
+ "'.");
}
//Serialize the object into a String
String value = Object2StringSerializer.serialize(jmi);
// Generate class
ClassWriter cw = generateJavaClass(className, value);
// Write class file on disk
writeJavaClass(className, cw, output);
return output + File.separatorChar + className;
}
private static ClassWriter generateJavaClass(final String className, final String value) {
ClassWriter cw = new ClassWriter(true);
String str = StringReplace.replaceChar(File.separatorChar, '/', className);
cw.visit(Constants.V1_1, Constants.ACC_PUBLIC, //access
str, //name
"org/objectweb/speedo/mapper/lib/Object2StringSerializer", //superName
new String[0], //interfaces
str // sourcefile
);
//implement an empty public constructor
CodeVisitor c = cw.visitMethod(Constants.ACC_PUBLIC, "<init>", "()V", null, null);
c.visitVarInsn(Constants.ALOAD, 0);
c.visitMethodInsn(
Constants.INVOKESPECIAL,
"org/objectweb/speedo/mapper/lib/Object2StringSerializer",
"<init>",
"()V");
c.visitInsn(Constants.RETURN);
c.visitMaxs(0, 0);
//implement the getSerializedObject method
c = cw.visitMethod(Constants.ACC_PUBLIC, "getSerializedObject", "()Ljava/lang/String;", null, null);
c.visitTypeInsn(Constants.NEW, "java/lang/StringBuffer");
c.visitInsn(Constants.DUP);
c.visitMethodInsn(Constants.INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V");
final int SPLIT_SIZE = 5000;
int nbSplit = value.length() / SPLIT_SIZE;
for (int i = 0; i < nbSplit; i++) {
int j = i * SPLIT_SIZE;
String s = value.substring(j, j + SPLIT_SIZE);
c.visitLdcInsn(s);
c.visitMethodInsn(
Constants.INVOKEVIRTUAL,
"java/lang/StringBuffer",
"append",
"(Ljava/lang/String;)Ljava/lang/StringBuffer;");
}
int last = value.length() % SPLIT_SIZE;
if (last > 0) {
c.visitLdcInsn(value.substring(SPLIT_SIZE * nbSplit));
c.visitMethodInsn(
Constants.INVOKEVIRTUAL,
"java/lang/StringBuffer",
"append",
"(Ljava/lang/String;)Ljava/lang/StringBuffer;");
}
c.visitMethodInsn(Constants.INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;");
c.visitInsn(Constants.ARETURN);
c.visitMaxs(1, 1);
return cw;
}
public static Object deserialize(String descFileName, ClassLoader cl, Logger logger)
throws Exception {
String className = descFileName2ClassName(descFileName);
if (className == null) {
throw new Exception("Impossible to load a null class");
}
Object2StringSerializer s = null;
className = StringReplace.replaceChar('/', '.', className);
if (logger != null) {
logger.log(BasicLevel.DEBUG, "Loading serialized object into the class '" + className + "'.");
}
try {
Class c = cl.loadClass(className);
s = (Object2StringSerializer) c.newInstance();
} catch (Throwable e) {
if (logger != null) {
logger.log(BasicLevel.ERROR, e.getMessage(), e);
}
ClassNotFoundException cnfe = new ClassNotFoundException("Impossible to load the jorm meta information: The class "
+ className + " is not availlable through the classloader (" + cl + ") of the persistent class", e);
throw cnfe;
}
return deserialize(s.getSerializedObject());
}
private static void writeJavaClass(final String name,
final ClassWriter jclass,
final String srcFiles) throws IOException {
int p = name.lastIndexOf(File.separatorChar);
String pkg;
String clas;
if (p == -1) {
pkg = "";
clas = name;
}
else {
pkg = name.substring(0, p);
clas = name.substring(p + 1);
}
File outputDir;
if (srcFiles == null) {
outputDir = new File(pkg);
}
else {
outputDir = new File(srcFiles + File.separatorChar + pkg);
}
outputDir.mkdirs();
File outputFile = new File(outputDir, clas + ".class");
outputFile.createNewFile();
FileOutputStream fos = new FileOutputStream(outputFile);
fos.write(jclass.toByteArray());
fos.close();
}
public static Object getObject(String descFileName, ClassLoader cl, Logger logger) throws Exception {
String className = descFileName2ClassName(descFileName);
logger.log(BasicLevel.DEBUG, "Loading serialized object into the class '" + className + "'.");
Object2StringSerializer s = null;
try {
s = (Object2StringSerializer) cl.loadClass(className).newInstance();
}
catch (Throwable e) {
ClassNotFoundException cnfe =
new ClassNotFoundException(
"Impossible to load the jorm meta information: The class "
+ className
+ " is not availlable through the classloader of the persistent class",
e);
logger.log(BasicLevel.ERROR, cnfe.getMessage(), cnfe);
throw cnfe;
}
return deserialize(s.getSerializedObject());
}
public static String descFileName2ClassName(String descFileName) {
return descFileName.substring(0, descFileName.length() - 4) + "SpeedoJMI";
}
/**
* @return the String containing a serialized java object
*/
public abstract String getSerializedObject();
}