KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > remote > LZReturnObject


1 /******************************************************************************
2  * LZReturnObject.java
3  * ****************************************************************************/

4
5 /* J_LZ_COPYRIGHT_BEGIN *******************************************************
6 * Copyright 2001-2004 Laszlo Systems, Inc. All Rights Reserved. *
7 * Use is subject to license terms. *
8 * J_LZ_COPYRIGHT_END *********************************************************/

9
10 package org.openlaszlo.remote;
11
12 import java.io.*;
13 import java.lang.reflect.*;
14 import java.util.*;
15 import java.lang.reflect.*;
16 import javax.servlet.http.*;
17 import org.openlaszlo.iv.flash.util.*;
18 import org.openlaszlo.iv.flash.api.action.*;
19 import org.openlaszlo.iv.flash.api.*;
20 import org.openlaszlo.utils.*;
21 import org.openlaszlo.xml.internal.*;
22 import org.apache.log4j.*;
23 import org.apache.commons.beanutils.PropertyUtils;
24
25 /**
26  * Utility class to create object SWF based on a server object.
27  */

28 public class LZReturnObject
29 {
30     public static Logger mLogger = Logger.getLogger(LZReturnObject.class);
31     public static final int RETTYPE_POJO = 0;
32     public static final int RETTYPE_JAVA_BEAN = 1;
33
34
35     int mCount = 0;
36     int mSize = 4096;
37     FlashBuffer mBody = new FlashBuffer(mSize);
38     Program mProgram = new Program(mBody);
39     DataContext mDC;
40     int mSWFVersion;
41     int mObjRetType;
42
43     public LZReturnObject(String JavaDoc objectReturnType, int swfversion) {
44         mDC = new DataContext();
45         mDC.setEncoding( swfversion == 5 ? "Cp1252" : "UTF-8" );
46         if (objectReturnType == null) {
47             mObjRetType = RETTYPE_POJO;
48         } else if ("javabean".equals(objectReturnType)){
49             mObjRetType = RETTYPE_JAVA_BEAN;
50         } else {
51             mObjRetType = RETTYPE_POJO;
52         }
53     }
54
55     void pushInteger(int i) {
56         mLogger.debug("pushInteger");
57         mProgram.push(i);
58     }
59
60     void pushFloat(float f) {
61         mLogger.debug("pushFloat");
62         mProgram.push(f);
63     }
64
65     void pushString(String JavaDoc s) {
66         mLogger.debug("pushString");
67         DataCommon.pushStringData(s, mBody, mDC);
68 // mProgram.push(s);
69
}
70
71     void pushDouble(double d) {
72         mLogger.debug("pushDouble");
73         mBody.writeByte(Actions.PushData);
74         mBody.writeWord(8+1);
75         mBody.writeByte(6);
76         long dbits = Double.doubleToLongBits(d);
77         mBody.writeDWord((int)(dbits>>>32));
78         mBody.writeDWord((int)(dbits&0xffffffffL));
79     }
80
81
82     void pushBoolean(boolean b) {
83         mLogger.debug("pushBoolean");
84         mBody.writeByte(Actions.PushData);
85         mBody.writeWord(1+1);
86         mBody.writeByte(5);
87         mBody.writeByte(b?1:0);
88     }
89
90     void pushArray(Object JavaDoc object) {
91         mLogger.debug("pushArray");
92         int length = Array.getLength(object);
93         for (int i = length - 1; 0 <= i; i--) {
94             createReturnValue(Array.get(object, i));
95         }
96         mProgram.push(length);
97         mBody.writeByte(Actions.InitArray);
98     }
99
100     void pushList(Object JavaDoc object) {
101         mLogger.debug("pushList");
102         List list = (List)object;
103         int length = list.size();
104         for (int i = length - 1; 0 <= i; i--) {
105             createReturnValue(list.get(i));
106         }
107         mProgram.push(length);
108         mBody.writeByte(Actions.InitArray);
109     }
110
111     void pushNull() {
112         mBody.writeByte(Actions.PushData);
113         mBody.writeWord(0+1);
114         mBody.writeByte(2);
115     }
116
117
118     void pushObject(Object JavaDoc object) {
119         Class JavaDoc cl = object.getClass();
120
121         // Does this have to be a unique name?
122
String JavaDoc varname = "__tmp" + (mCount++);
123         String JavaDoc classname = cl.getName();
124
125         //------------------------------------------------------------
126
// varname = new Object();
127
mProgram.push(varname);
128         {
129             // new Object()
130
mProgram.push(0); // zero arguments
131
mProgram.push("Object"); // push classname
132
mProgram.newObject(); // instantiate
133
}
134         mProgram.setVar();
135
136
137         //------------------------------------------------------------
138
// varname.class = classname
139
mProgram.push(varname);
140         mProgram.getVar();
141         mProgram.push("class");
142         mProgram.push(classname);
143         mBody.writeByte(Actions.SetMember);
144
145         if (mObjRetType == RETTYPE_JAVA_BEAN) {
146             pushObjectJavaBean(object, varname);
147         } else {
148             pushObjectPOJO(object, varname);
149         }
150      
151         //------------------------------------------------------------
152
// add varname object into stack
153
mProgram.push(varname);
154         mProgram.getVar();
155     }
156
157     /**
158      * Create SWF for an object that conforms to JavaBean spec.
159      */

160     void pushObjectPOJO(Object JavaDoc object, String JavaDoc varname) {
161         Class JavaDoc cl = object.getClass();
162         Field[] fields = cl.getFields();
163         for (int i=0; i < fields.length; i++) {
164             if (! Modifier.isPublic(fields[i].getModifiers()))
165                 continue;
166
167             String JavaDoc fieldName = fields[i].getName();
168             Object JavaDoc value;
169             try {
170                 value = fields[i].get(object);
171             } catch (IllegalAccessException JavaDoc e) {
172                 mLogger.error("IllegalAccessException", e);
173                 continue;
174             }
175             if (mLogger.isDebugEnabled()) {
176                 mLogger.debug("add field name " + fieldName + ", " +
177                               (value != null ? value.getClass() : null) );
178             }
179             mProgram.push(varname);
180             mProgram.getVar();
181             mProgram.push(fieldName);
182             createReturnValue(value);
183             mBody.writeByte(Actions.SetMember);
184         }
185     }
186
187     /**
188      * Create SWF for an object that conforms to JavaBean spec.
189      */

190     void pushObjectJavaBean(Object JavaDoc object, String JavaDoc varname) {
191         //------------------------------------------------------------
192
// Just get the fields from the objects and add it to this object
193
Map beanProps = null;
194         try {
195             //Use jakarta-commons beanutils to inspect the object
196
beanProps = PropertyUtils.describe(object);
197         } catch (IllegalAccessException JavaDoc e) {
198             mLogger.error("IllegalAccessException",e);
199         } catch (InvocationTargetException e) {
200             mLogger.error("InvocationTargetException",e);
201         } catch (NoSuchMethodException JavaDoc e) {
202             mLogger.error("NoSuchMethodException",e);
203         }
204                     
205         if (beanProps != null) {
206             Set keys = beanProps.keySet();
207             Iterator iter = keys.iterator();
208             while(iter.hasNext()){
209                 String JavaDoc fieldName = (String JavaDoc)iter.next();
210                 //Don't add the class property as it is already set by the method
211
if(!"class".equals(fieldName)) {
212                     Object JavaDoc value = beanProps.get(fieldName);
213                     if (mLogger.isDebugEnabled()) {
214                         mLogger.debug("add field name " + fieldName + ", " +
215                                       ((value!=null)?value.getClass():null));
216                     }
217                     mProgram.push(varname);
218                     mProgram.getVar();
219                     mProgram.push((String JavaDoc)fieldName);
220                     createReturnValue(value);
221                     mBody.writeByte(Actions.SetMember);
222                 }
223             }
224         }
225     }
226
227
228     void pushMap(Map map) {
229
230         // Does this have to be a unique name?
231
String JavaDoc varname = "__tmp" + (mCount++);
232
233         //------------------------------------------------------------
234
// varname = new Object();
235
mProgram.push(varname);
236         {
237             // new Object()
238
mProgram.push(0); // zero arguments
239
mProgram.push("Object"); // push classname
240
mProgram.newObject(); // instantiate
241
}
242         mProgram.setVar();
243
244         Iterator iter = map.keySet().iterator();
245
246         while (iter.hasNext()) {
247             String JavaDoc key = (String JavaDoc)iter.next();
248
249             //------------------------------------------------------------
250
// varname.class = classname
251
mProgram.push(varname);
252             mProgram.getVar();
253             mProgram.push(key);
254             createReturnValue(map.get(key));
255             mBody.writeByte(Actions.SetMember);
256         }
257
258
259         //------------------------------------------------------------
260
// add varname object into stack
261
mProgram.push(varname);
262         mProgram.getVar();
263     }
264
265     /**
266      * Recurse through this function to create return value
267      */

268     void createReturnValue(Object JavaDoc object) {
269         mLogger.debug("createReturnValue");
270         if (object == null) {
271             pushNull();
272             return;
273         }
274
275         Class JavaDoc cl = object.getClass();
276         if (cl.isArray()) {
277             pushArray(object);
278         } else if (List.class.isInstance(object)) {
279             pushList(object);
280         } else if (Map.class.isInstance(object)) {
281             pushMap((Map)object);
282         } else if (cl == Integer JavaDoc.class) {
283             pushInteger(((Integer JavaDoc)object).intValue());
284         } else if (cl == Long JavaDoc.class) {
285             //------------------------------------------------------------
286
// From: http://developer.irt.org/script/1031.htm
287
//
288
// In JavaScript all numbers are floating-point numbers.
289
//
290
// JavaScript uses the standard 8 byte IEEE floating-point numeric
291
// format, which means the range is from:
292
//
293
// +/- 1.7976931348623157x10^308 - very large, and +/- 5x10^-324 -
294
// very small.
295
//
296
// As JavaScript uses floating-point numbers the accuracy is only
297
// assured for integers between: -9,007,199,254,740,992 (-2^53) and
298
// 9,007,199,254,740,992 (2^53)
299
//
300
// All the above from "JavaScript The Definitive Guide" - O'Reilly.
301
//
302
//------------------------------------------------------------
303
// Java long:
304
// 8 bytes signed (two's complement). Ranges from
305
// -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807.
306
//------------------------------------------------------------
307

308             // possible rounding inaccuracy
309
pushInteger(((Long JavaDoc)object).intValue());
310
311         } else if (cl == Short JavaDoc.class) {
312             pushInteger(((Short JavaDoc)object).intValue());
313         } else if (cl == Byte JavaDoc.class) {
314             // push as number for now
315
pushInteger(((Byte JavaDoc)object).intValue());
316         } else if (cl == Character JavaDoc.class) {
317             pushString(((Character JavaDoc)object).toString());
318         } else if (cl == Float JavaDoc.class) {
319             pushFloat(((Float JavaDoc)object).floatValue());
320         } else if (cl == Double JavaDoc.class) {
321             pushDouble(((Double JavaDoc)object).doubleValue());
322         } else if (cl == Boolean JavaDoc.class) {
323             pushBoolean(((Boolean JavaDoc)object).booleanValue());
324         } else if (cl == String JavaDoc.class) {
325             pushString((String JavaDoc)object);
326         } else {
327             pushObject(object);
328         }
329     }
330
331
332     /**
333      *
334      */

335     public Program createObjectProgram(Object JavaDoc object) {
336         mLogger.debug("createObjectProgram(" + object + ")" );
337
338         createReturnValue(object);
339
340         //------------------------------------------------------------
341
// call into the viewsystem
342
mProgram.push("_parent");
343         mProgram.getVar();
344         mProgram.push(2);
345         mProgram.push("_parent");
346         mProgram.getVar();
347         mProgram.push("loader");
348         mBody.writeByte(Actions.GetMember);
349         mProgram.push("returnData");
350         mProgram.callMethod();
351         mProgram.pop();
352
353         // Borrowed from DataCompiler. -pk
354

355         // Collect the string dictionary data
356
byte pooldata[] = DataCommon.makeStringPool(mDC);
357
358         // Room at the end of the buffer for maybe some callback code to the
359
// runtime to say we're done.
360
final int MISC = 4096;
361
362         // 'out' is the main FlashBuffer for composing the output file
363
FlashBuffer out = new FlashBuffer(mBody.getSize() + pooldata.length + MISC);
364         // Write out string constant pool
365
out._writeByte( Actions.ConstantPool );
366         out._writeWord( pooldata.length + 2 ); // number of bytes in pool data + int (# strings)
367
out._writeWord( mDC.cpool.size() ); // number of strings in pool
368
out.writeArray( pooldata, 0, pooldata.length); // copy the data
369

370         // Write out the code to build nodes
371
out.writeArray(mBody.getBuf(), 0, mBody.getSize());
372         return new Program(out);
373     }
374
375
376     /**
377      */

378     public static FlashFile createObjectFile(Object JavaDoc object, String JavaDoc objectReturnType,
379                                              int swfversion)
380         throws IOException {
381         mLogger.debug("createObjectFile(" + object + ", " + swfversion + ")" );
382         // Create FlashFile object nd include action bytes
383
FlashFile file = FlashFile.newFlashFile();
384         Script s = new Script(1);
385         file.setMainScript(s);
386         file.setVersion(swfversion);
387         Frame frame = s.newFrame();
388         Program program = new LZReturnObject(objectReturnType, swfversion)
389             .createObjectProgram(object);
390         frame.addFlashObject(new DoAction(program));
391         return file;
392     }
393
394     /**
395      * @param objectReturnType One of 'pojo' (returns public member values) or
396      * 'javabean' (returns members that have associated getters). Will default
397      * to 'pojo'.
398      */

399     public static byte[] createObject(Object JavaDoc object, String JavaDoc objectReturnType,
400                                       int swfversion)
401         throws IOException {
402         mLogger.debug("createObject(" + object + ")" );
403
404         int i = 0;
405         try {
406             FlashFile file = createObjectFile(object, objectReturnType,
407                                               swfversion);
408             FlashOutput fob = file.generate();
409             byte[] buf = new byte[fob.getSize()];
410             System.arraycopy(fob.getBuf(), 0, buf, 0, fob.getSize());
411             return buf;
412         } catch (IVException e) {
413             throw new ChainedException(e);
414         } catch (IOException e) {
415             mLogger.error("io error creating object SWF: " + e.getMessage());
416             throw e;
417         }
418     }
419
420 }
421
Popular Tags