1 16 17 18 package org.apache.xmlrpc.applet; 19 20 import java.io.IOException ; 21 import java.io.InputStream ; 22 import java.io.OutputStream ; 23 import java.io.UnsupportedEncodingException ; 24 import java.net.MalformedURLException ; 25 import java.net.URL ; 26 import java.net.URLConnection ; 27 import java.text.DateFormat ; 28 import java.text.ParseException ; 29 import java.text.SimpleDateFormat ; 30 import java.util.Date ; 31 import java.util.Enumeration ; 32 import java.util.Hashtable ; 33 import java.util.Stack ; 34 import java.util.Vector ; 35 import org.apache.commons.codec.binary.Base64; 36 import org.apache.commons.codec.DecoderException; 37 import org.apache.commons.codec.EncoderException; 38 import org.xml.sax.AttributeList ; 39 import org.xml.sax.HandlerBase ; 40 import org.xml.sax.InputSource ; 41 import org.xml.sax.SAXException ; 42 import org.xml.sax.SAXParseException ; 43 import uk.co.wilson.xml.MinML; 44 45 52 public class SimpleXmlRpcClient 53 { 54 URL url; 55 56 59 public SimpleXmlRpcClient(URL url) 60 { 61 this.url = url; 62 } 63 64 67 public SimpleXmlRpcClient(String url) throws MalformedURLException 68 { 69 this.url = new URL (url); 70 } 71 72 75 public SimpleXmlRpcClient(String hostname, int port) 76 throws MalformedURLException 77 { 78 this.url = new URL ("http://" + hostname + ":" + port + "/RPC2"); 79 } 80 81 89 public Object execute(String method, Vector params) 90 throws XmlRpcException, IOException 91 { 92 return new XmlRpcSupport (url).execute (method, params); 93 } 94 } 95 96 99 class XmlRpcSupport extends HandlerBase 100 { 101 102 URL url; 103 String methodName; 104 boolean fault = false; 105 Object result = null; 106 107 Base64 base64 = new Base64(); 108 109 Stack values; 111 Value currentValue; 112 113 boolean readCdata; 114 115 static final DateFormat format = new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ss"); 117 118 StringBuffer cdata = new StringBuffer (); 120 121 static final int STRING = 0; 123 static final int INTEGER = 1; 124 static final int BOOLEAN = 2; 125 static final int DOUBLE = 3; 126 static final int DATE = 4; 127 static final int BASE64 = 5; 128 static final int STRUCT = 6; 129 static final int ARRAY = 7; 130 131 public static boolean debug = false; 133 final static String types[] = {"String", "Integer", "Boolean", "Double", 134 "Date", "Base64", "Struct", "Array"}; 135 136 137 141 public XmlRpcSupport(URL url) 142 { 143 this.url = url; 144 } 145 146 149 public static void setDebug(boolean val) 150 { 151 debug = val; 152 } 153 154 158 synchronized void parse(InputStream is) throws Exception 159 { 160 values = new Stack (); 161 long now = System.currentTimeMillis(); 162 MinML parser = new MinML(); 163 parser.setDocumentHandler(this); 164 parser.setErrorHandler(this); 165 166 parser.parse(new InputSource (is)); 167 168 if (debug) 169 { 170 System.out.println("Spent " + (System.currentTimeMillis() - now) 171 + " parsing"); 172 } 173 } 174 175 178 void writeObject (Object what, XmlWriter writer) throws IOException 179 { 180 writer.startElement("value"); 181 if (what instanceof String ) 182 { 183 writer.write(what.toString()); 184 } 185 else if (what instanceof Integer ) 186 { 187 writer.startElement("int"); 188 writer.write (what.toString()); 189 writer.endElement("int"); 190 } 191 else if (what instanceof Boolean ) 192 { 193 writer.startElement("boolean"); 194 writer.write(((Boolean ) what).booleanValue() ? "1" : "0"); 195 writer.endElement("boolean"); 196 } 197 else if (what instanceof Double ) 198 { 199 writer.startElement("double"); 200 writer.write (what.toString()); 201 writer.endElement("double"); 202 } 203 else if (what instanceof Date ) 204 { 205 writer.startElement("dateTime.iso8601"); 206 Date d = (Date ) what; 207 writer.write(format.format(d)); 208 writer.endElement("dateTime.iso8601"); 209 } 210 else if (what instanceof byte[]) 211 { 212 writer.startElement("base64"); 213 try 214 { 215 writer.write((byte[]) base64.encode(what)); 216 } 217 catch (EncoderException e) 218 { 219 throw new RuntimeException ("Possibly incompatible version " + 220 "of '" + Base64.class.getName() + 221 "' used: " + e); 222 } 223 writer.endElement("base64"); 224 } 225 else if (what instanceof Vector ) 226 { 227 writer.startElement("array"); 228 writer.startElement("data"); 229 Vector v = (Vector ) what; 230 int l2 = v.size(); 231 for (int i2 = 0; i2 < l2; i2++) 232 { 233 writeObject(v.elementAt(i2), writer); 234 } 235 writer.endElement("data"); 236 writer.endElement("array"); 237 } 238 else if (what instanceof Hashtable ) 239 { 240 writer.startElement("struct"); 241 Hashtable h = (Hashtable ) what; 242 for (Enumeration e = h.keys (); e.hasMoreElements (); ) 243 { 244 String nextkey = (String ) e.nextElement (); 245 Object nextval = h.get(nextkey); 246 writer.startElement("member"); 247 writer.startElement("name"); 248 writer.write(nextkey); 249 writer.endElement("name"); 250 writeObject(nextval, writer); 251 writer.endElement("member"); 252 } 253 writer.endElement("struct"); 254 } 255 else 256 { 257 String unsupportedType = what == null ? "null" 258 : what.getClass().toString(); 259 throw new IOException ("unsupported Java type: " + unsupportedType); 260 } 261 writer.endElement("value"); 262 } 263 264 272 public Object execute(String method, Vector arguments) 273 throws XmlRpcException, IOException 274 { 275 fault = false; 276 long now = System.currentTimeMillis(); 277 try 278 { 279 StringBuffer strbuf = new StringBuffer (); 280 XmlWriter writer = new XmlWriter(strbuf); 281 writeRequest(writer, method, arguments); 282 byte[] request = strbuf.toString().getBytes(); 283 URLConnection con = url.openConnection(); 284 con.setDoOutput(true); 285 con.setDoInput(true); 286 con.setUseCaches(false); 287 con.setAllowUserInteraction(false); 288 con.setRequestProperty("Content-Length", 289 Integer.toString(request.length)); 290 con.setRequestProperty("Content-Type", "text/xml"); 291 OutputStream out = con.getOutputStream(); 293 out.write(request); 294 out.flush(); 295 InputStream in = con.getInputStream(); 296 parse(in); 297 System.out.println("result = " + result); 298 } 299 catch (Exception x) 300 { 301 x.printStackTrace(); 302 throw new IOException (x.getMessage()); 303 } 304 if (fault) 305 { 306 XmlRpcException exception = null; 308 try 309 { 310 Hashtable f = (Hashtable ) result; 311 String faultString = (String ) f.get("faultString"); 312 int faultCode = Integer.parseInt(f.get("faultCode").toString()); 313 exception = new XmlRpcException(faultCode, faultString.trim()); 314 } 315 catch (Exception x) 316 { 317 throw new XmlRpcException(0, "Invalid fault response"); 318 } 319 throw exception; 320 } 321 System.out.println("Spent " + (System.currentTimeMillis() - now) 322 + " in request"); 323 return result; 324 } 325 326 329 void objectParsed(Object what) 330 { 331 result = what; 332 } 333 334 337 void writeRequest (XmlWriter writer, String method, Vector params) 338 throws IOException 339 { 340 writer.startElement("methodCall"); 341 writer.startElement("methodName"); 342 writer.write(method); 343 writer.endElement("methodName"); 344 writer.startElement("params"); 345 int l = params.size(); 346 for (int i = 0; i < l; i++) 347 { 348 writer.startElement("param"); 349 writeObject(params.elementAt (i), writer); 350 writer.endElement("param"); 351 } 352 writer.endElement("params"); 353 writer.endElement("methodCall"); 354 } 355 356 359 362 public void characters(char ch[], int start, int length) 363 throws SAXException 364 { 365 if (! readCdata) 366 { 367 return; 368 } 369 cdata.append (ch, start, length); 370 } 371 372 375 public void endElement(String name) throws SAXException 376 { 377 if (debug) 378 { 379 System.err.println("endElement: " + name); 380 } 381 382 if (currentValue != null && readCdata) 384 { 385 currentValue.characterData(cdata.toString()); 386 cdata.setLength(0); 387 readCdata = false; 388 } 389 390 if ("value".equals(name)) 391 { 392 int depth = values.size(); 393 if (depth < 2 || values.elementAt (depth - 2).hashCode () != STRUCT) 396 { 397 Value v = currentValue; 398 values.pop(); 399 if (depth < 2) 400 { 401 objectParsed(v.value); 403 currentValue = null; 404 } 405 else 406 { 407 currentValue = (Value) values.peek(); 409 currentValue.endElement(v); 410 } 411 } 412 } 413 414 if ("member".equals(name)) 416 { 417 Value v = currentValue; 418 values.pop(); 419 currentValue = (Value) values.peek(); 420 currentValue.endElement(v); 421 } 422 423 else if ("methodName".equals(name)) 424 { 425 methodName = cdata.toString(); 426 cdata.setLength(0); 427 readCdata = false; 428 } 429 } 430 431 434 public void startElement (String name, AttributeList atts) 435 throws SAXException 436 { 437 if (debug) 438 { 439 System.err.println("startElement: " + name); 440 } 441 442 if ("value".equals(name)) 443 { 444 Value v = new Value(); 446 values.push(v); 447 currentValue = v; 448 cdata.setLength(0); 450 readCdata = true; 451 } 452 else if ("methodName".equals(name)) 453 { 454 cdata.setLength(0); 455 readCdata = true; 456 } 457 else if ("name".equals(name)) 458 { 459 cdata.setLength(0); 460 readCdata = true; 461 } 462 else if ("string".equals(name)) 463 { 464 cdata.setLength(0); 466 readCdata = true; 467 } 468 else if ("i4".equals(name) || "int".equals(name)) 469 { 470 currentValue.setType(INTEGER); 471 cdata.setLength(0); 472 readCdata = true; 473 } 474 else if ("boolean".equals(name)) 475 { 476 currentValue.setType(BOOLEAN); 477 cdata.setLength(0); 478 readCdata = true; 479 } 480 else if ("double".equals(name)) 481 { 482 currentValue.setType(DOUBLE); 483 cdata.setLength(0); 484 readCdata = true; 485 } 486 else if ("dateTime.iso8601".equals(name)) 487 { 488 currentValue.setType(DATE); 489 cdata.setLength(0); 490 readCdata = true; 491 } 492 else if ("base64".equals(name)) 493 { 494 currentValue.setType(BASE64); 495 cdata.setLength(0); 496 readCdata = true; 497 } 498 else if ("struct".equals(name)) 499 { 500 currentValue.setType(STRUCT); 501 } 502 else if ("array".equals(name)) 503 { 504 currentValue.setType(ARRAY); 505 } 506 } 507 508 513 public void error(SAXParseException e) throws SAXException 514 { 515 System.err.println("Error parsing XML: " + e); 516 } 519 520 525 public void fatalError(SAXParseException e) throws SAXException 526 { 527 System.err.println("Fatal error parsing XML: " + e); 528 } 531 532 535 class Value 536 { 537 int type; 538 Object value; 539 String nextMemberName; 541 542 Hashtable struct; 543 Vector array; 544 545 548 public Value() 549 { 550 this.type = STRING; 551 } 552 553 556 public void endElement(Value child) 557 { 558 if (type == ARRAY) 559 { 560 array.addElement(child.value); 561 } 562 else if (type == STRUCT) 563 { 564 struct.put(nextMemberName, child.value); 565 } 566 } 567 568 572 public void setType(int type) 573 { 574 this.type = type; 576 if (type == ARRAY) 577 { 578 value = array = new Vector (); 579 } 580 if (type == STRUCT) 581 { 582 value = struct = new Hashtable (); 583 } 584 } 585 586 590 public void characterData (String cdata) 591 { 592 switch (type) 593 { 594 case INTEGER: 595 value = new Integer (cdata.trim()); 596 break; 597 case BOOLEAN: 598 value = new Boolean ("1".equals(cdata.trim())); 599 break; 600 case DOUBLE: 601 value = new Double (cdata.trim()); 602 break; 603 case DATE: 604 try 605 { 606 value = format.parse(cdata.trim()); 607 } 608 catch (ParseException p) 609 { 610 throw new RuntimeException (p.getMessage()); 612 } 613 break; 614 case BASE64: 615 try 616 { 617 value = base64.decode((Object ) cdata.getBytes()); 618 } 619 catch (DecoderException e) { 620 625 value = cdata; 626 } 627 break; 628 case STRING: 629 value = cdata; 630 break; 631 case STRUCT: 632 nextMemberName = cdata; 634 break; 635 } 636 } 637 638 643 public int hashCode () 644 { 645 return type; 646 } 647 648 652 public String toString () 653 { 654 return (types[type] + " element " + value); 655 } 656 } 657 658 666 class XmlWriter 667 { 668 StringBuffer buf; 669 String enc; 670 671 675 public XmlWriter(StringBuffer buf) 676 { 677 this.buf = buf; 678 buf.append("<?xml version=\"1.0\"?>"); 679 } 680 681 685 public void startElement(String elem) 686 { 687 buf.append("<"); 688 buf.append(elem); 689 buf.append(">"); 690 } 691 692 696 public void endElement(String elem) 697 { 698 buf.append("</"); 699 buf.append(elem); 700 buf.append(">"); 701 } 702 703 707 public void emptyElement(String elem) 708 { 709 buf.append("<"); 710 buf.append(elem); 711 buf.append("/>"); 712 } 713 714 718 public void chardata(String text) 719 { 720 int l = text.length(); 721 for (int i = 0; i < l; i++) 722 { 723 char c = text.charAt(i); 724 switch (c) 725 { 726 case '<' : 727 buf.append("<"); 728 break; 729 case '>' : 730 buf.append(">"); 731 break; 732 case '&' : 733 buf.append("&"); 734 break; 735 default : 736 buf.append(c); 737 } 738 } 739 } 740 741 745 public void write(byte[] text) 746 { 747 for (int i = 0; i < text.length; i++) 751 { 752 buf.append((char) text[i]); 753 } 754 } 755 756 760 public void write(char[] text) 761 { 762 buf.append(text); 763 } 764 765 769 public void write(String text) 770 { 771 buf.append(text); 772 } 773 774 778 public String toString() 779 { 780 return buf.toString(); 781 } 782 783 788 public byte[] getBytes() throws UnsupportedEncodingException 789 { 790 return buf.toString().getBytes(); 791 } 792 } 793 } 794 | Popular Tags |