1 4 5 9 10 package org.openlaszlo.xml.internal; 11 12 import java.io.*; 13 import java.util.*; 14 import org.w3c.dom.*; 15 import org.xml.sax.*; 16 import javax.xml.parsers.*; 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.ChainedException; 21 import org.openlaszlo.utils.FileUtils; 22 import org.apache.log4j.*; 23 24 27 public class XMLRPCCompiler 28 { 29 public static Logger mLogger = Logger.getLogger(XMLRPCCompiler.class); 30 31 private static DocumentBuilderFactory factory = null; 32 33 private FlashBuffer body; 34 private Program program; 35 36 39 static DocumentBuilderFactory getDocumentBuilderFactory() { 40 if (factory == null) { 41 try { 42 factory = DocumentBuilderFactory.newInstance(); 43 } catch (FactoryConfigurationError e) { 44 throw new RuntimeException (e.getMessage()); 45 } 46 } 47 return factory; 48 } 49 50 51 56 static List getElementsByTagName(Element parent, String tag) 57 { 58 List list = new Vector(); 59 NodeList children = parent.getChildNodes(); 60 61 for (int i=0; i < children.getLength(); i++) { 62 Node node = children.item(i); 63 if (node.getNodeType() == Node.ELEMENT_NODE) { 64 list.add((Element)node); 65 } 66 } 67 return list; 68 } 69 70 75 static Element getChildElement(Element parent, int n) { 76 NodeList children = parent.getChildNodes(); 77 int count = 0; 78 for (int i=0; i < children.getLength(); i++) { 79 Node node = children.item(i); 80 if (node.getNodeType() == Node.ELEMENT_NODE) { 81 if (n == count++) { 82 mLogger.debug("found " + node.getNodeName()); 83 return (Element)node; 84 } 85 } 86 } 87 return null; 88 } 89 90 94 static String getFirstChildTextString(Element parent) { 95 Node text = parent.getFirstChild(); 96 return text != null && text.getNodeType() == Node.TEXT_NODE 97 ? ( (Text)text ).getData() : ""; 98 } 99 100 104 void writeString(String string) 105 throws IOException { 106 mLogger.debug("writeString"); 107 program.push(string); 108 } 109 110 114 void writeInteger(String intval) 115 throws IOException { 116 mLogger.debug("writeInteger"); 117 try { 118 program.push(Integer.parseInt(intval)); 119 } catch (NumberFormatException e) { 120 throw new IOException(e.getMessage()); 121 } 122 } 123 124 129 void writeDouble(String doubleval) 130 throws IOException { 131 mLogger.debug("writeDouble"); 132 try { 133 body.writeByte(Actions.PushData); 136 body.writeWord(8+1); 137 body.writeByte(6); 138 long dbits = Double.doubleToLongBits(Double.parseDouble(doubleval)); 139 body.writeDWord((int)(dbits>>>32)); 140 body.writeDWord((int)(dbits&0xffffffffL)); 141 } catch (NumberFormatException e) { 142 throw new IOException(e.getMessage()); 143 } 144 } 145 146 149 void pushBoolean(boolean b) 150 { 151 body.writeByte(Actions.PushData); 152 body.writeWord(1+1); 153 body.writeByte(5); 154 body.writeByte(b?1:0); 155 } 156 157 161 void writeBoolean(String booleanval) 162 throws IOException { 163 mLogger.debug("writeBoolean"); 164 try { 165 pushBoolean(Integer.parseInt(booleanval) != 0); 166 } catch (NumberFormatException e) { 167 if (booleanval.equals("false")) 168 pushBoolean(false); 169 else if (booleanval.equals("true")) 170 pushBoolean(true); 171 else 172 throw new IOException("not a boolean value"); 173 } 174 } 175 176 180 void writeArray(Element array) 181 throws IOException { 182 mLogger.debug("writeArray"); 183 List data = getElementsByTagName(array, "data"); 184 if (data.size() != 1) 185 throw new IOException("Invalid number of data elements in array"); 186 187 List values = getElementsByTagName((Element)data.get(0), "value"); 188 for (int i = values.size()-1; i >= 0; --i) { 189 writeValue((Element)values.get(i)); 190 } 191 program.push(values.size()); 193 body.writeByte(Actions.InitArray); 194 } 195 196 200 void writeStruct(Element struct) 201 throws IOException { 202 mLogger.debug("writeStruct"); 203 List members = getElementsByTagName(struct, "member"); 204 for (int i = members.size()-1; i >= 0; --i) { 206 writeMember((Element)members.get(i)); 207 } 208 program.push(members.size()); 210 body.writeByte(Actions.InitObject); 211 } 212 213 217 void writeMember(Element member) 218 throws IOException { 219 mLogger.debug("writeMember"); 220 Element name = getChildElement(member, 0); 221 Element value = getChildElement(member, 1); 222 if (name == null || value == null) 223 throw new IOException("Name or value appears to be null."); 224 if (! name.getNodeName().equals("name")) 225 throw new IOException("Name does not appear to be the first argument in member"); 226 if (! value.getNodeName().equals("value")) 227 throw new IOException("Value does not appear to be the second argument in member"); 228 229 program.push(getFirstChildTextString(name)); 231 writeValue(value); 232 } 233 234 237 void writeDateTime(Element datetimeval) 238 throws RuntimeException { 239 mLogger.debug("writeDateTime"); 240 throw new RuntimeException ("datetime.iso8601 unimplemented"); 241 } 242 243 246 void writeBase64(Element base64val) { 247 mLogger.debug("writeBase64"); 248 throw new RuntimeException ("base64 unimplemented"); 249 } 250 251 252 256 void writeValue(Element value) 257 throws IOException { 258 mLogger.debug("writeValue"); 259 260 Element type = getChildElement(value, 0); 261 if (type == null) { 262 writeString(getFirstChildTextString(value)); 263 return; 264 } 265 266 String t = type.getTagName(); 267 if (t.equals("string")) { 268 writeString(getFirstChildTextString(type)); 269 } else if (t.equals("int") || t.equals("i4")) { 270 writeInteger(getFirstChildTextString(type)); 271 } else if (t.equals("double")) { 272 writeDouble(getFirstChildTextString(type)); 273 } else if (t.equals("boolean")) { 274 writeBoolean(getFirstChildTextString(type)); 275 } else if (t.equals("struct")) { 276 writeStruct(type); 277 } else if (t.equals("array")) { 278 writeArray(type); 279 } else if (t.equals("dateTime.iso8601")) { 280 writeDateTime(type); 281 } else if (t.equals("base64")) { 282 writeBase64(type); 283 } 284 } 285 286 289 void writeParams(Element params) 290 throws IOException { 291 mLogger.debug("writeParams"); 292 293 Element param = getChildElement(params, 0); 294 if (! param.getTagName().equals("param")) 295 throw new IOException("Invalid params body"); 296 297 Element value = getChildElement(param, 0); 298 if (! value.getTagName().equals("value")) 299 throw new IOException("Invalid param body"); 300 301 writeValue(value); 302 } 303 304 308 void writeFault(Element fault) 309 throws IOException { 310 mLogger.debug("writeFault"); 311 312 Element value = getChildElement(fault, 0); 313 if (! value.getTagName().equals("value")) 314 throw new IOException("Invalid param body"); 315 316 writeValue(value); 317 } 318 319 322 void writeXMLRPCData(Element element) 323 throws IOException { 324 mLogger.debug("writeXMLRPCData"); 325 326 if (! element.getTagName().equals("methodResponse")) 327 throw new IOException("Invalid XMLRPC response"); 328 329 Element child = getChildElement(element, 0); 330 if (child != null) { 331 if (child.getTagName().equals("params")) { 332 writeParams(child); 333 return; 334 } else if (child.getTagName().equals("fault")) { 335 writeFault(child); 336 return; 337 } 338 } 339 throw new IOException("bad XMLRPC message body"); 342 } 343 344 345 353 public Program makeProgram(Element element, int xmlsize) 354 throws IOException { 355 mLogger.debug("makeProgram"); 356 357 final int MISC = 4096; 360 body = new FlashBuffer((int) (Math.floor(xmlsize * 3) + MISC)); 363 program = new Program(body); 364 365 writeXMLRPCData(element); 366 367 program.push("_parent"); 369 program.getVar(); 370 program.push(2); 371 program.push("_parent"); 372 program.getVar(); 373 program.push("loader"); 374 body.writeByte(Actions.GetMember); 375 program.push("returnData"); 376 program.callMethod(); 377 program.pop(); 378 379 return program; 380 } 381 382 383 389 public FlashFile makeSWF(Element element, int xmlsize, int swfversion) 390 throws IOException { 391 mLogger.debug("makeSWF"); 392 393 FlashFile file = FlashFile.newFlashFile(); 395 Script s = new Script(1); 396 file.setMainScript(s); 397 file.setVersion(swfversion); 398 Frame frame = s.newFrame(); 399 Program program = makeProgram(element, xmlsize); 400 frame.addFlashObject(new DoAction(program)); 401 return file; 402 } 403 404 405 411 public byte[] getSWF(Element element, int xmlsize, int swfversion) 412 throws IOException { 413 mLogger.debug("getSWF"); 414 int i = 0; 415 try { 416 FlashFile file = makeSWF(element, xmlsize, swfversion); 417 FlashOutput fob = file.generate(); 418 byte[] buf = new byte[fob.getSize()]; 419 System.arraycopy(fob.getBuf(), 0, buf, 0, fob.getSize()); 420 return buf; 421 } catch (IVException e) { 422 throw new ChainedException(e); 423 } catch (IOException e) { 424 mLogger.error("io error getting SWF: " + e.getMessage()); 425 throw e; 426 } 427 } 428 429 432 public static byte[] compile(String xmlrpc, int swfversion) 433 throws IOException { 434 return compile(new StringReader(xmlrpc), xmlrpc.length(), swfversion); 435 } 436 437 442 public static byte[] compile(Reader reader, int xmlsize, int swfversion) 443 throws IOException { 444 mLogger.debug("compile(reader,xmlsize,swfversion)"); 445 try { 446 DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder(); 448 Document document = builder.parse(new InputSource(reader)); 449 return new XMLRPCCompiler().getSWF(document.getDocumentElement(), xmlsize, swfversion); 450 } catch (Exception e) { 451 mLogger.error("Caught exception at compile: " + e); 452 StringWriter trace = new StringWriter(); 453 e.printStackTrace(new PrintWriter(trace)); 454 return compileFault(trace.toString(), swfversion); 455 } 456 } 457 458 459 public static String xmlFaultResponse(int code, String message) { 460 return new StringBuffer ("<?xml version=\"1.0\"?>") 461 .append("<methodResponse>") 462 .append("<fault>") 463 .append("<value>") 464 .append("<struct>") 465 .append("<member>") 466 .append("<name>faultCode</name>") 467 .append("<value><int>").append(code).append("</int></value>") 468 .append("</member>") 469 .append("<member>") 470 .append("<name>faultString</name>") 471 .append("<value><string>") 472 .append(message) 473 .append("</string></value>") 474 .append("</member>") 475 .append("</struct>") 476 .append("</value>") 477 .append("</fault>") 478 .append("</methodResponse>") 479 .toString(); 480 } 481 482 public static byte[] compileResponse(int code, String message, int swfversion) 483 throws IOException { 484 String fault = xmlFaultResponse(code, message); 485 try { 486 DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder(); 487 Document document = builder.parse 488 (new InputSource(new StringReader(fault))); 489 return new XMLRPCCompiler().getSWF(document.getDocumentElement(), fault.length(), swfversion); 490 } catch (Exception e) { 491 mLogger.error("Caught exception at compileFault: " + message, e); 492 throw new IOException(e.getMessage()); 493 } 494 } 495 496 499 public static byte[] compileFault(String message, int swfversion) throws IOException { 500 return compileResponse(-1, message, swfversion); 501 } 502 503 504 507 public static void main(String [] args) { 508 System.out.println("args: " + args.length); 509 if (args.length != 1) { 510 System.err.println("Usage: XMLRPCCompiler xmlrpcfile"); 511 return; 512 } 513 try { 514 File file = new File(args[0]); 515 InputStream in = new ByteArrayInputStream(compile(new FileReader(file), 516 (int)file.length(), 6)); 517 OutputStream out = new FileOutputStream("xmlrpc.swf"); 518 FileUtils.send(in, out, 4096); 519 } catch (Exception e) { 520 e.printStackTrace(); 521 } 522 } 523 } 524 | Popular Tags |