001: /******************************************************************************
002: * LZClientObject.java
003: * ****************************************************************************/package org.openlaszlo.remote;
004:
005: import java.io.*;
006: import java.lang.reflect.*;
007: import javax.servlet.http.*;
008: import org.openlaszlo.iv.flash.util.*;
009: import org.openlaszlo.iv.flash.api.action.*;
010: import org.openlaszlo.iv.flash.api.*;
011: import org.openlaszlo.utils.*;
012: import org.openlaszlo.xml.internal.DataCommon;
013: import org.openlaszlo.xml.internal.DataContext;
014: import org.apache.log4j.*;
015:
016: /**
017: * Utility class to create object SWF based on a server object.
018: */
019: public class LZClientObject {
020: public static Logger mLogger = Logger
021: .getLogger(LZClientObject.class);
022:
023: /**
024: */
025: public static Program createObjectProgram(String classname,
026: String scope, Class c) {
027: if (mLogger.isDebugEnabled()) {
028: mLogger.debug("createObjectProgram(" + classname + ","
029: + "," + scope + "," + c.getName() + ")");
030: }
031:
032: int size = 4096;
033: FlashBuffer body = new FlashBuffer(size);
034: Program program = new Program(body);
035: DataContext dc = new DataContext();
036:
037: //------------------------------------------------------------
038: // Tells client data returned is an object
039: // this.__LZstub = true
040: program.push("__LZstubload");
041: program.push(1);
042:
043: // SOAP specific information
044: // object.stubinfo
045: program.push("stubinfo");
046: {
047: //------------------------------------------------------------
048: // this.remoteClass = classname
049: program.push("remoteClass");
050: DataCommon.pushStringData(classname, body, dc);
051: }
052: program.push(1);
053: body.writeByte(Actions.InitObject);
054:
055: // object.stub
056: program.push("stub");
057: {
058: int count = 0;
059: boolean onlyStatic = "staticobject".equals(scope);
060:
061: //------------------------------------------------------------
062: // Create methods for object
063: Method[] methods = c.getMethods();
064: for (int i = 0; i < methods.length; i++) {
065:
066: // Skip Object methods
067: if (methods[i].getDeclaringClass() == Object.class) {
068: continue;
069: }
070:
071: // Check if we only want static methods
072: if (onlyStatic
073: && !Modifier
074: .isStatic(methods[i].getModifiers())) {
075: continue;
076: }
077:
078: // Skip toString method.
079: String methodName = methods[i].getName();
080: if ("toString".equals(methodName)) {
081: continue;
082: }
083:
084: count++;
085:
086: //------------------------------------------------------------
087: //
088: DataCommon.pushStringData(methodName, body, dc);
089: body.writeByte(Actions.DefineFunction);
090: body.writeWord(5); // length of header (1 byte + 2 words (2bytes))
091: body.writeByte(0); // function name string (if empty, it is
092: // anonymous)
093: body.writeWord(0); // number of parameters
094: {
095: // Check to see if method's last two parameters are
096: // HttpServletRequest and HttpServletResponse.
097: Class[] params = methods[i].getParameterTypes();
098: int len = params.length;
099: boolean doreq = // next to last or last argument
100: (len > 1 && params[len - 2] == HttpServletRequest.class)
101: || (len > 0 && params[len - 1] == HttpServletRequest.class);
102: boolean dores = // should be last argument
103: (len > 0 && params[len - 1] == HttpServletResponse.class);
104:
105: FlashBuffer fbuf = new FlashBuffer(500);
106: Program fprog = new Program(fbuf);
107:
108: // arguments.callee.args gets set in the client and includes
109: // secure and secureport information.
110: //
111: // var args = arguments.callee.args;
112: DataCommon.pushStringData("args", fbuf, dc);
113: {
114: DataCommon
115: .pushStringData("arguments", fbuf, dc);
116: fprog.getVar();
117: DataCommon.pushStringData("callee", fbuf, dc);
118: fbuf.writeByte(Actions.GetMember);
119: DataCommon.pushStringData("args", fbuf, dc);
120: fbuf.writeByte(Actions.GetMember);
121: }
122: fprog.setVar();
123:
124: // _root.LzRemote.invoke(
125: // arguments,
126: // delegate,
127: // classname,
128: // classname + "." + methodName,
129: // { op: 'session', doreq..., dores... },
130: // this.secure,
131: // this.secureport
132: // );
133:
134: // 5. secureport
135: DataCommon.pushStringData("args", fbuf, dc);
136: fprog.getVar();
137: DataCommon.pushStringData("secureport", fbuf, dc);
138: fbuf.writeByte(Actions.GetMember);
139:
140: // 4. secure
141: DataCommon.pushStringData("args", fbuf, dc);
142: fprog.getVar();
143: DataCommon.pushStringData("secure", fbuf, dc);
144: fbuf.writeByte(Actions.GetMember);
145:
146: // 3. opts
147: int optcount = 0;
148: {
149: // { op: 'invoke', oname: varname, scope: scope,
150: // objectreturntype: objectreturntype,
151: // doreq: TBD, dores: TBD}
152: DataCommon.pushStringData("op", fbuf, dc);
153: DataCommon.pushStringData("invoke", fbuf, dc);
154: optcount++;
155:
156: DataCommon.pushStringData("objectreturntype",
157: fbuf, dc);
158: {
159: DataCommon.pushStringData("args", fbuf, dc);
160: fprog.getVar();
161: DataCommon.pushStringData(
162: "objectreturntype", fbuf, dc);
163: fbuf.writeByte(Actions.GetMember);
164: }
165: optcount++;
166:
167: DataCommon.pushStringData("oname", fbuf, dc);
168: {
169: DataCommon.pushStringData("args", fbuf, dc);
170: fprog.getVar();
171: DataCommon.pushStringData("attributename",
172: fbuf, dc);
173: fbuf.writeByte(Actions.GetMember);
174: }
175: optcount++;
176:
177: DataCommon.pushStringData("scope", fbuf, dc);
178: {
179: DataCommon.pushStringData("args", fbuf, dc);
180: fprog.getVar();
181: DataCommon
182: .pushStringData("scope", fbuf, dc);
183: fbuf.writeByte(Actions.GetMember);
184: }
185: optcount++;
186:
187: DataCommon.pushStringData("methodname", fbuf,
188: dc);
189: DataCommon.pushStringData(classname + "."
190: + methodName, fbuf, dc);
191: optcount++;
192:
193: DataCommon
194: .pushStringData("classname", fbuf, dc);
195: DataCommon.pushStringData(classname, fbuf, dc);
196: optcount++;
197:
198: if (doreq) {
199: DataCommon
200: .pushStringData("doreq", fbuf, dc);
201: fprog.push(1);
202: optcount++;
203: }
204: if (dores) {
205: DataCommon
206: .pushStringData("dores", fbuf, dc);
207: fprog.push(1);
208: optcount++;
209: }
210: }
211: fprog.push(optcount); // # of object values
212: fbuf.writeByte(Actions.InitObject);
213:
214: // 2. arguments[0] (should be array of arguments)
215: DataCommon.pushStringData("arguments", fbuf, dc);
216: fprog.getVar();
217: fprog.push(0);
218: fbuf.writeByte(Actions.GetMember);
219:
220: // 1. arguments[1] (should be delegate)
221: DataCommon.pushStringData("arguments", fbuf, dc);
222: fprog.getVar();
223: fprog.push(1);
224: fbuf.writeByte(Actions.GetMember);
225:
226: // Number of parameters
227: fprog.push(5);
228:
229: // call function
230: DataCommon.pushStringData("_root", fbuf, dc);
231: fprog.getVar();
232: DataCommon.pushStringData("LzJavaRPCService", fbuf,
233: dc);
234: fbuf.writeByte(Actions.GetMember);
235: DataCommon.pushStringData("invoke", fbuf, dc);
236: fprog.callMethod();
237:
238: // return seqnum from invoke()
239: fbuf.writeByte(Actions.Return);
240:
241: body.writeWord(fbuf.pos); // length of defined function body
242: body.writeFOB(fbuf);
243: }
244: }
245: program.push(count);
246: body.writeByte(Actions.InitObject);
247: }
248:
249: program.push(3);
250: body.writeByte(Actions.InitObject);
251:
252: //------------------------------------------------------------
253: // call into the viewsystem
254: program.push("_parent");
255: program.getVar();
256: program.push(2);
257: program.push("_parent");
258: program.getVar();
259: program.push("loader");
260: body.writeByte(Actions.GetMember);
261: program.push("returnData");
262: program.callMethod();
263: program.pop();
264:
265: // Collect the string dictionary data
266: byte pooldata[] = DataCommon.makeStringPool(dc);
267: // 'out' is the main FlashBuffer for composing the output file
268: final int MISC = 64;
269: FlashBuffer out = new FlashBuffer(body.getSize()
270: + pooldata.length + MISC);
271: // Write out string constant pool
272: out.writeByte(Actions.ConstantPool);
273: out.writeWord(pooldata.length + 2); // number of bytes in pool data + int (# strings)
274: out.writeWord(dc.cpool.size()); // number of strings in pool
275: out.writeArray(pooldata, 0, pooldata.length); // copy the data
276: // Write out the code to build nodes
277: out.writeArray(body.getBuf(), 0, body.getSize());
278:
279: return new Program(out);
280: }
281:
282: /**
283: */
284: public static FlashFile createObjectFile(String classname,
285: String scope, Class c, int swfversion) throws IOException {
286: if (mLogger.isDebugEnabled()) {
287: mLogger.debug("createObjectFile(" + classname + ","
288: + c.getName() + ")");
289: }
290: // Create FlashFile object nd include action bytes
291: FlashFile file = FlashFile.newFlashFile();
292: Script s = new Script(1);
293: file.setMainScript(s);
294: file.setVersion(swfversion);
295: Frame frame = s.newFrame();
296: Program program = createObjectProgram(classname, scope, c);
297: frame.addFlashObject(new DoAction(program));
298: return file;
299: }
300:
301: /**
302: */
303: public static byte[] createObject(String classname, String scope,
304: int swfversion) throws IOException {
305: if (mLogger.isDebugEnabled()) {
306: mLogger.debug("createObject(" + classname + "," + scope
307: + ")");
308: }
309:
310: Class c;
311: try {
312: c = Class.forName(classname);
313: } catch (ClassNotFoundException e) {
314: throw new RuntimeException("Can't find class " + classname);
315: }
316:
317: int i = 0;
318: try {
319: FlashFile file = createObjectFile(classname, scope, c,
320: swfversion);
321: FlashOutput fob = file.generate();
322: byte[] buf = new byte[fob.getSize()];
323: System.arraycopy(fob.getBuf(), 0, buf, 0, fob.getSize());
324: return buf;
325: } catch (IVException e) {
326: throw new ChainedException(e);
327: } catch (IOException e) {
328: mLogger.error("io error creating object SWF: "
329: + e.getMessage());
330: throw e;
331: }
332: }
333:
334: }
|