001: /**
002: * Copyright (C) 2001-2004 France Telecom R&D
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */package org.objectweb.speedo.mapper.lib;
018:
019: import org.objectweb.util.monolog.api.Logger;
020: import org.objectweb.util.monolog.api.BasicLevel;
021: import org.objectweb.speedo.api.Debug;
022: import org.objectweb.speedo.tools.StringReplace;
023: import org.objectweb.asm.ClassWriter;
024: import org.objectweb.asm.Constants;
025: import org.objectweb.asm.CodeVisitor;
026:
027: import java.io.IOException;
028: import java.io.ObjectOutputStream;
029: import java.io.ObjectInputStream;
030: import java.io.ByteArrayInputStream;
031: import java.io.File;
032: import java.io.FileOutputStream;
033:
034: /**
035: * This class contains primitive to serialize and deserialize an Object into a
036: * java Stirng.
037: *
038: * @author S.Chassande-Barrioz
039: */
040: public abstract class Object2StringSerializer {
041:
042: public final static String DESC_FILE_NAME_PROP = "descFileName";
043:
044: /**
045: * Serializes an object into a String
046: *
047: * @param o is the java object to serialize
048: * @return the java object serialized into a String
049: * @throws java.io.IOException occurs if the java serialization fails
050: */
051: public static String serialize(Object o) throws IOException {
052: java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
053: ObjectOutputStream oos = new ObjectOutputStream(baos);
054: oos.writeObject(o);
055: oos.close();
056: byte[] bs = baos.toByteArray();
057: baos.close();
058: StringBuffer sb = new StringBuffer(bs.length);
059: for (int i = 0; i < bs.length; i++) {
060: sb.append((char) (bs[i] & 0XFF));
061: }
062: return sb.toString();
063: }
064:
065: /**
066: * Deserializes a String into a java object.
067: *
068: * @param s is the string containing a serialized java object
069: * @return the deserialized java object
070: * @throws IOException occurs if the deserialization fails
071: * @throws ClassNotFoundException occurs a class of a deserialized java
072: * object is not present.
073: */
074: public static Object deserialize(String s) throws IOException,
075: ClassNotFoundException {
076: byte[] bs = new byte[s.length()];
077: for (int i = 0; i < bs.length; i++) {
078: bs[i] = (byte) s.charAt(i);
079: }
080: ObjectInputStream ois = new ObjectInputStream(
081: new ByteArrayInputStream(bs));
082: Object o = ois.readObject();
083: ois.close();
084: return o;
085: }
086:
087: public static String serialize(String output, String descFileName,
088: Object jmi, Logger logger) throws IOException {
089: String className = descFileName2ClassName(descFileName);
090:
091: if (Debug.ON && logger.isLoggable(BasicLevel.DEBUG)) {
092: logger.log(BasicLevel.DEBUG,
093: "Serialize the Jorm Meta Information into the class '"
094: + className + "' into the directory '"
095: + output + "'.");
096: }
097:
098: //Serialize the object into a String
099: String value = Object2StringSerializer.serialize(jmi);
100:
101: // Generate class
102: ClassWriter cw = generateJavaClass(className, value);
103: // Write class file on disk
104:
105: writeJavaClass(className, cw, output);
106:
107: return output + File.separatorChar + className;
108: }
109:
110: private static ClassWriter generateJavaClass(
111: final String className, final String value) {
112:
113: ClassWriter cw = new ClassWriter(true);
114:
115: String str = StringReplace.replaceChar(File.separatorChar, '/',
116: className);
117:
118: cw
119: .visit(Constants.V1_1,
120: Constants.ACC_PUBLIC, //access
121: str, //name
122: "org/objectweb/speedo/mapper/lib/Object2StringSerializer", //superName
123: new String[0], //interfaces
124: str // sourcefile
125: );
126: //implement an empty public constructor
127: CodeVisitor c = cw.visitMethod(Constants.ACC_PUBLIC, "<init>",
128: "()V", null, null);
129: c.visitVarInsn(Constants.ALOAD, 0);
130: c
131: .visitMethodInsn(
132: Constants.INVOKESPECIAL,
133: "org/objectweb/speedo/mapper/lib/Object2StringSerializer",
134: "<init>", "()V");
135: c.visitInsn(Constants.RETURN);
136: c.visitMaxs(0, 0);
137:
138: //implement the getSerializedObject method
139: c = cw.visitMethod(Constants.ACC_PUBLIC, "getSerializedObject",
140: "()Ljava/lang/String;", null, null);
141: c.visitTypeInsn(Constants.NEW, "java/lang/StringBuffer");
142: c.visitInsn(Constants.DUP);
143: c.visitMethodInsn(Constants.INVOKESPECIAL,
144: "java/lang/StringBuffer", "<init>", "()V");
145: final int SPLIT_SIZE = 5000;
146: int nbSplit = value.length() / SPLIT_SIZE;
147: for (int i = 0; i < nbSplit; i++) {
148: int j = i * SPLIT_SIZE;
149: String s = value.substring(j, j + SPLIT_SIZE);
150: c.visitLdcInsn(s);
151: c.visitMethodInsn(Constants.INVOKEVIRTUAL,
152: "java/lang/StringBuffer", "append",
153: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
154: }
155: int last = value.length() % SPLIT_SIZE;
156: if (last > 0) {
157: c.visitLdcInsn(value.substring(SPLIT_SIZE * nbSplit));
158: c.visitMethodInsn(Constants.INVOKEVIRTUAL,
159: "java/lang/StringBuffer", "append",
160: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
161: }
162: c.visitMethodInsn(Constants.INVOKEVIRTUAL,
163: "java/lang/StringBuffer", "toString",
164: "()Ljava/lang/String;");
165: c.visitInsn(Constants.ARETURN);
166: c.visitMaxs(1, 1);
167:
168: return cw;
169: }
170:
171: public static Object deserialize(String descFileName,
172: ClassLoader cl, Logger logger) throws Exception {
173: String className = descFileName2ClassName(descFileName);
174: if (className == null) {
175: throw new Exception("Impossible to load a null class");
176: }
177: Object2StringSerializer s = null;
178: className = StringReplace.replaceChar('/', '.', className);
179: if (logger != null) {
180: logger.log(BasicLevel.DEBUG,
181: "Loading serialized object into the class '"
182: + className + "'.");
183: }
184: try {
185: Class c = cl.loadClass(className);
186: s = (Object2StringSerializer) c.newInstance();
187: } catch (Throwable e) {
188: if (logger != null) {
189: logger.log(BasicLevel.ERROR, e.getMessage(), e);
190: }
191: ClassNotFoundException cnfe = new ClassNotFoundException(
192: "Impossible to load the jorm meta information: The class "
193: + className
194: + " is not availlable through the classloader ("
195: + cl + ") of the persistent class", e);
196: throw cnfe;
197: }
198: return deserialize(s.getSerializedObject());
199: }
200:
201: private static void writeJavaClass(final String name,
202: final ClassWriter jclass, final String srcFiles)
203: throws IOException {
204: int p = name.lastIndexOf(File.separatorChar);
205:
206: String pkg;
207: String clas;
208: if (p == -1) {
209: pkg = "";
210: clas = name;
211: } else {
212: pkg = name.substring(0, p);
213: clas = name.substring(p + 1);
214: }
215: File outputDir;
216: if (srcFiles == null) {
217: outputDir = new File(pkg);
218: } else {
219: outputDir = new File(srcFiles + File.separatorChar + pkg);
220: }
221:
222: outputDir.mkdirs();
223: File outputFile = new File(outputDir, clas + ".class");
224: outputFile.createNewFile();
225: FileOutputStream fos = new FileOutputStream(outputFile);
226: fos.write(jclass.toByteArray());
227: fos.close();
228: }
229:
230: public static Object getObject(String descFileName, ClassLoader cl,
231: Logger logger) throws Exception {
232: String className = descFileName2ClassName(descFileName);
233:
234: logger.log(BasicLevel.DEBUG,
235: "Loading serialized object into the class '"
236: + className + "'.");
237: Object2StringSerializer s = null;
238: try {
239: s = (Object2StringSerializer) cl.loadClass(className)
240: .newInstance();
241: } catch (Throwable e) {
242: ClassNotFoundException cnfe = new ClassNotFoundException(
243: "Impossible to load the jorm meta information: The class "
244: + className
245: + " is not availlable through the classloader of the persistent class",
246: e);
247: logger.log(BasicLevel.ERROR, cnfe.getMessage(), cnfe);
248: throw cnfe;
249: }
250: return deserialize(s.getSerializedObject());
251: }
252:
253: public static String descFileName2ClassName(String descFileName) {
254: return descFileName.substring(0, descFileName.length() - 4)
255: + "SpeedoJMI";
256: }
257:
258: /**
259: * @return the String containing a serialized java object
260: */
261: public abstract String getSerializedObject();
262:
263: }
|