001: /******************************************************************************
002: * ClientSOAPService.java
003: * ****************************************************************************/package org.openlaszlo.remote.swf.soap;
004:
005: import java.io.*;
006: import java.util.*;
007: import javax.xml.namespace.QName;
008:
009: import org.openlaszlo.iv.flash.api.*;
010: import org.openlaszlo.iv.flash.api.action.*;
011: import org.openlaszlo.iv.flash.util.*;
012: import org.openlaszlo.utils.*;
013: import org.openlaszlo.xml.internal.DataCommon;
014: import org.openlaszlo.xml.internal.DataContext;
015: import org.apache.log4j.Logger;
016:
017: public class ClientSOAPService {
018: public static Logger mLogger = Logger
019: .getLogger(ClientSOAPService.class);
020:
021: public static Program createObjectProgram(LZSOAPService service) {
022:
023: int size = 4096;
024: FlashBuffer body = new FlashBuffer(size);
025: Program program = new Program(body);
026: DataContext dc = new DataContext();
027:
028: // object.__LZstubload
029: //------------------------------------------------------------
030: // Tells client data returned is an object
031: // this.__LZstubload = true
032: program.push("__LZstubload");
033: program.push(1);
034:
035: // SOAP specific information
036: // object.stubinfo
037: program.push("stubinfo");
038: {
039: //------------------------------------------------------------
040: // this.service = service.getServiceName()
041: program.push("service");
042: DataCommon.pushStringData(service.getServiceName(), body,
043: dc);
044:
045: //------------------------------------------------------------
046: // this.port = service.getPort()
047: program.push("port");
048: DataCommon.pushStringData(service.getPort(), body, dc);
049:
050: //------------------------------------------------------------
051: // this.wsdl = service.getWSDL()
052: program.push("wsdl");
053: DataCommon.pushStringData(service.getWSDL(), body, dc);
054:
055: //------------------------------------------------------------
056: // this.ctypes = <complexTypeInfoObject>
057: program.push("__LZctypes");
058: pushComplexTypeInfo(program, service
059: .getSchemaComplexTypes(), dc);
060:
061: //------------------------------------------------------------
062: // this._namespace = namespace /* target namespace */
063: program.push("__LZnamespace");
064: program.push(service.getTargetNS());
065: }
066: program.push(5);
067: body.writeByte(Actions.InitObject);
068:
069: // object.stub
070: program.push("stub");
071: {
072: int count = 0;
073: //------------------------------------------------------------
074: // Create client-side service operations. Assuming that
075: // operations won't be null.
076: //------------------------------------------------------------
077: Map operations = service.getOperations();
078: Iterator iter = operations.keySet().iterator();
079: while (iter.hasNext()) {
080:
081: String opName = (String) iter.next();
082: LZSOAPOperation op = (LZSOAPOperation) operations
083: .get(opName);
084:
085: if (mLogger.isDebugEnabled()) {
086: mLogger.debug(
087: /* (non-Javadoc)
088: * @i18n.test
089: * @org-mes="adding operation: " + p[0]
090: */
091: org.openlaszlo.i18n.LaszloMessages.getMessage(
092: ClientSOAPService.class.getName(),
093: "051018-99", new Object[] { opName }));
094: }
095:
096: //------------------------------------------------------------
097: //
098: count++;
099: DataCommon.pushStringData(opName, body, dc);
100: body.writeByte(Actions.DefineFunction);
101: body.writeWord(5); // length of header (1 byte + 2 words (2bytes))
102: body.writeByte(0); // function name string (if empty, it is
103: // anonymous)
104: body.writeWord(0); // number of parameters
105: {
106:
107: FlashBuffer fbuf = new FlashBuffer(500);
108: Program fprog = new Program(fbuf);
109:
110: // arguments.callee.args gets set in the client and includes
111: // secure and secureport information.
112: //
113: // var args = arguments.callee.args;
114: DataCommon.pushStringData("args", fbuf, dc);
115: {
116: DataCommon
117: .pushStringData("arguments", fbuf, dc);
118: fprog.getVar();
119: DataCommon.pushStringData("callee", fbuf, dc);
120: fbuf.writeByte(Actions.GetMember);
121: DataCommon.pushStringData("args", fbuf, dc);
122: fbuf.writeByte(Actions.GetMember);
123: }
124: fprog.setVar();
125:
126: // _root.LzSOAP.invoke(
127: // delegate,
128: // args
129: // header
130: // opts, /* wsdl, service, port, operation, parts */
131: // this.secure,
132: // this.secureport,
133: // );
134:
135: // 6. secureport
136: DataCommon.pushStringData("args", fbuf, dc);
137: fprog.getVar();
138: DataCommon.pushStringData("superclass", fbuf, dc);
139: fbuf.writeByte(Actions.GetMember);
140: DataCommon.pushStringData("secureport", fbuf, dc);
141: fbuf.writeByte(Actions.GetMember);
142:
143: // 5. secure
144: DataCommon.pushStringData("args", fbuf, dc);
145: fprog.getVar();
146: DataCommon.pushStringData("superclass", fbuf, dc);
147: fbuf.writeByte(Actions.GetMember);
148: DataCommon.pushStringData("secure", fbuf, dc);
149: fbuf.writeByte(Actions.GetMember);
150:
151: // 4. opts
152: {
153: // 6. argument array of parameter type tuples like:
154: // [
155: // [ name1, element1, type1(qname) ],
156: // [ name2, element2, type2(qname) ]
157: // ]
158: DataCommon.pushStringData("parts", fbuf, dc);
159: pushParts(fprog, op.getInputMessage(), op
160: .getStyle(), dc);
161:
162: // 5. operation type
163: DataCommon.pushStringData("opstyle", fbuf, dc);
164: DataCommon.pushStringData(op.getStyle(), fbuf,
165: dc);
166:
167: // 4. operation name
168: DataCommon
169: .pushStringData("operation", fbuf, dc);
170: DataCommon.pushStringData(opName, fbuf, dc);
171:
172: // 3. SOAP port
173: DataCommon.pushStringData("port", fbuf, dc);
174: DataCommon.pushStringData(service.getPort(),
175: fbuf, dc);
176:
177: // 2. SOAP service
178: DataCommon.pushStringData("service", fbuf, dc);
179: DataCommon.pushStringData(service
180: .getServiceName(), fbuf, dc);
181:
182: // 1. SOAP wsdl
183: DataCommon.pushStringData("wsdl", fbuf, dc);
184: DataCommon.pushStringData(service.getWSDL(),
185: fbuf, dc);
186: }
187: fprog.push(6);
188: fbuf.writeByte(Actions.InitObject);
189:
190: // 3. requestheaders
191: DataCommon.pushStringData("args", fbuf, dc);
192: fprog.getVar();
193: DataCommon.pushStringData("superclass", fbuf, dc);
194: fbuf.writeByte(Actions.GetMember);
195: DataCommon.pushStringData("requestheaders", fbuf,
196: dc);
197: fbuf.writeByte(Actions.GetMember);
198:
199: // 2. arguments[0] (should be array of arguments)
200: DataCommon.pushStringData("arguments", fbuf, dc);
201: fprog.getVar();
202: fprog.push(0);
203: fbuf.writeByte(Actions.GetMember);
204:
205: // 1. arguments[1] (should be delegate)
206: DataCommon.pushStringData("arguments", fbuf, dc);
207: fprog.getVar();
208: fprog.push(1);
209: fbuf.writeByte(Actions.GetMember);
210:
211: // Number of parameters
212: fprog.push(6);
213:
214: // call function
215: DataCommon.pushStringData("_root", fbuf, dc);
216: fprog.getVar();
217: DataCommon
218: .pushStringData("LzSOAPService", fbuf, dc);
219: fbuf.writeByte(Actions.GetMember);
220: DataCommon.pushStringData("invoke", fbuf, dc);
221:
222: fprog.callMethod();
223:
224: // return seqnum from invoke()
225: fbuf.writeByte(Actions.Return);
226:
227: body.writeWord(fbuf.pos); // length of defined function body
228: body.writeFOB(fbuf);
229: }
230: }
231: program.push(count);
232: body.writeByte(Actions.InitObject);
233: }
234:
235: program.push(3);
236: body.writeByte(Actions.InitObject);
237:
238: //------------------------------------------------------------
239: // call into the viewsystem
240: program.push("_parent");
241: program.getVar();
242: program.push(2);
243: program.push("_parent");
244: program.getVar();
245: program.push("loader");
246: body.writeByte(Actions.GetMember);
247: program.push("returnData");
248: program.callMethod();
249: program.pop();
250:
251: // Collect the string dictionary data
252: byte pooldata[] = DataCommon.makeStringPool(dc);
253: // 'out' is the main FlashBuffer for composing the output file
254: final int MISC = 64;
255: FlashBuffer out = new FlashBuffer(body.getSize()
256: + pooldata.length + MISC);
257: // Write out string constant pool
258: out.writeByte(Actions.ConstantPool);
259: out.writeWord(pooldata.length + 2); // number of bytes in pool data + int (# strings)
260: out.writeWord(dc.cpool.size()); // number of strings in pool
261: out.writeArray(pooldata, 0, pooldata.length); // copy the data
262: // Write out the code to build nodes
263: out.writeArray(body.getBuf(), 0, body.getSize());
264:
265: return new Program(out);
266: }
267:
268: static void pushParts(Program program, LZSOAPMessage inMesg,
269: String style, DataContext dc) {
270:
271: FlashBuffer body = program.body();
272: if (inMesg == null) {
273: LZSOAPUtils.pushNull(body);
274: return;
275: }
276:
277: List parts = inMesg.getParts();
278: for (int i = parts.size() - 1; i >= 0; i--) {
279: LZSOAPPart part = (LZSOAPPart) parts.get(i);
280: String name = part.getName();
281: String element = part.getElement();
282: ComplexType type = part.getType();
283: QName typeName = (type != null ? type.getName() : null);
284:
285: LZSOAPUtils.pushQName(program, typeName, dc);
286: if (style.equals("rpc")) {
287: // rpc calls use the name of the part as the name of element.
288: LZSOAPUtils.pushString(program, name, dc);
289: } else {
290: // documents use element name
291: LZSOAPUtils.pushString(program, element, dc);
292: }
293: program.push(2);
294: body.writeByte(Actions.InitArray);
295: }
296: program.push(parts.size());
297: body.writeByte(Actions.InitArray);
298: }
299:
300: /**
301: * @param program Program
302: * @param ctm complex type map
303: */
304: public static void pushComplexTypeInfo(Program program, Map ctm,
305: DataContext dc) {
306: FlashBuffer body = program.body();
307: if (ctm == null) {
308: LZSOAPUtils.pushNull(body);
309: return;
310: }
311:
312: Iterator iter = ctm.entrySet().iterator();
313: if (!iter.hasNext()) {
314: LZSOAPUtils.pushNull(body);
315: return;
316: }
317:
318: int nattrs = 0;
319: while (iter.hasNext()) {
320: Map.Entry entry = (Map.Entry) iter.next();
321: ComplexType ct = (ComplexType) entry.getValue();
322:
323: DataCommon.pushStringData(ct.getName().getLocalPart(),
324: body, dc);
325: {
326: // namespace
327: DataCommon.pushStringData("ns", body, dc);
328: DataCommon.pushStringData(ct.getName()
329: .getNamespaceURI(), body, dc);
330:
331: // type is one of simple, complex, array
332: DataCommon.pushStringData("type", body, dc);
333: DataCommon.pushStringData(ct.getTypeString(), body, dc);
334:
335: // QName for array type; null if complex type is not an array
336: DataCommon.pushStringData("typeQ", body, dc);
337: LZSOAPUtils.pushQName(program, ct
338: .getArrayItemTypeQName(), dc);
339:
340: // push members
341: DataCommon.pushStringData("members", body, dc);
342: pushMembers(program, ct, dc);
343:
344: // push base
345: ComplexType base = ct.getBase();
346: QName baseQName = (base != null ? base
347: .getArrayItemTypeQName() : null);
348: DataCommon.pushStringData("base", body, dc);
349: LZSOAPUtils.pushQName(program, baseQName, dc);
350:
351: program.push(5);
352: body.writeByte(Actions.InitObject);
353: }
354: nattrs++;
355: }
356:
357: program.push(nattrs);
358: body.writeByte(Actions.InitObject);
359: }
360:
361: /**
362: * Push members of a complex type.
363: */
364: static void pushMembers(Program program, ComplexType ct,
365: DataContext dc) {
366: FlashBuffer body = program.body();
367: Map members = ct.getMembers();
368: if (members == null) {
369: LZSOAPUtils.pushNull(body);
370: return;
371: }
372:
373: Iterator iter = members.entrySet().iterator();
374: if (!iter.hasNext()) {
375: LZSOAPUtils.pushNull(body);
376: return;
377: }
378:
379: int count = 0;
380: while (iter.hasNext()) {
381: Map.Entry entry = (Map.Entry) iter.next();
382: String key = (String) entry.getKey();
383: QName value = (QName) entry.getValue();
384: DataCommon.pushStringData(key, body, dc);
385: LZSOAPUtils.pushQName(program, value, dc);
386: count++;
387: }
388:
389: ComplexType baseType = ct.getBase();
390: if (baseType != null) {
391: count += pushBaseMembers(program, baseType, dc);
392: }
393:
394: program.push(count);
395: body.writeByte(Actions.InitObject);
396: }
397:
398: /**
399: * Push base members and returns count of members added. Helper method for
400: * pushMembers().
401: * @return count of members pushed
402: */
403: static int pushBaseMembers(Program program, ComplexType ct,
404: DataContext dc) {
405:
406: Map members = ct.getMembers();
407: if (members == null)
408: return 0;
409:
410: Iterator iter = members.entrySet().iterator();
411: if (!iter.hasNext())
412: return 0;
413:
414: int count = 0;
415: FlashBuffer body = program.body();
416: while (iter.hasNext()) {
417: Map.Entry entry = (Map.Entry) iter.next();
418: String key = (String) entry.getKey();
419: QName value = (QName) entry.getValue();
420: DataCommon.pushStringData(key, body, dc);
421: LZSOAPUtils.pushQName(program, value, dc);
422: count++;
423: }
424:
425: ComplexType baseType = ct.getBase();
426: if (baseType != null) {
427: count += pushBaseMembers(program, baseType, dc);
428: }
429: return count;
430: }
431:
432: /**
433: */
434: public static FlashFile createObjectFile(LZSOAPService service,
435: int swfnum) throws IOException {
436: // Create FlashFile object nd include action bytes
437: FlashFile file = FlashFile.newFlashFile();
438: Script s = new Script(1);
439: file.setMainScript(s);
440: file.setVersion(swfnum);
441: Frame frame = s.newFrame();
442: Program program = createObjectProgram(service);
443: frame.addFlashObject(new DoAction(program));
444: return file;
445: }
446:
447: /**
448: */
449: public static byte[] createObject(LZSOAPService service, int swfnum)
450: throws IOException {
451:
452: int i = 0;
453: try {
454: FlashFile file = createObjectFile(service, swfnum);
455: FlashOutput fob = file.generate();
456: byte[] buf = new byte[fob.getSize()];
457: System.arraycopy(fob.getBuf(), 0, buf, 0, fob.getSize());
458: return buf;
459: } catch (IVException e) {
460: throw new ChainedException(e);
461: } catch (IOException e) {
462: mLogger.error(
463: /* (non-Javadoc)
464: * @i18n.test
465: * @org-mes="io error creating object SWF: " + p[0]
466: */
467: org.openlaszlo.i18n.LaszloMessages.getMessage(
468: ClientSOAPService.class.getName(), "051018-462",
469: new Object[] { e.getMessage() }));
470: throw e;
471: }
472: }
473:
474: }
|