1 18 package org.enhydra.barracuda.contrib.sam.xmlform.dtd; 19 20 import java.io.File ; 22 import java.io.FileReader ; 23 import java.io.FileWriter ; 24 import java.io.InputStream ; 25 import java.io.InputStreamReader ; 26 import java.io.IOException ; 27 import java.io.OutputStream ; 28 import java.io.OutputStreamWriter ; 29 import java.io.Reader ; 30 import java.io.Writer ; 31 import java.util.HashMap ; 32 import java.util.Iterator ; 33 import java.util.Map ; 34 import org.xml.sax.EntityResolver ; 35 import org.xml.sax.ErrorHandler ; 36 import org.xml.sax.InputSource ; 37 import org.xml.sax.Locator ; 38 import org.xml.sax.SAXException ; 39 import org.xml.sax.SAXParseException ; 40 import org.xml.sax.XMLReader ; 41 import org.xml.sax.ext.LexicalHandler ; 42 import org.xml.sax.helpers.DefaultHandler ; 43 import org.xml.sax.helpers.XMLReaderFactory ; 44 45 import java.util.Iterator ; 47 import java.util.List ; 48 import java.util.LinkedList ; 49 50 public class ValidatorImpl extends DefaultHandler implements Cloneable , Unmarshallable, LexicalHandler , Validator { 51 52 private List paraList; 53 private List validatorList; 54 private String classname; 55 private boolean zeus_ClassnameSet; 56 57 58 private String docTypeString; 59 60 61 private String outputEncoding; 62 63 64 private Unmarshallable zeus_currentUNode; 65 66 67 private Unmarshallable zeus_parentUNode; 68 69 70 private boolean zeus_thisNodeHandled = false; 71 72 73 private boolean hasDTD; 74 75 76 private boolean validate; 77 78 79 private Map namespaceMappings; 80 81 82 private static EntityResolver entityResolver; 83 84 85 private static ErrorHandler errorHandler; 86 87 private static ValidatorImpl prototype = null; 88 89 public static void setPrototype(ValidatorImpl prototype) { 90 ValidatorImpl.prototype = prototype; 91 } 92 public static ValidatorImpl newInstance() { 93 try { 94 return (prototype!=null)?(ValidatorImpl)prototype.clone(): new ValidatorImpl(); 95 } catch (CloneNotSupportedException e) { 96 return null; } 98 } 99 public ValidatorImpl() { 100 paraList = new LinkedList (); 101 validatorList = new LinkedList (); 102 zeus_ClassnameSet = false; 103 docTypeString = ""; 104 hasDTD = false; 105 validate = false; 106 namespaceMappings = new HashMap (); 107 } 108 109 public List getParaList() { 110 return paraList; 111 } 112 113 public void setParaList(List paraList) { 114 this.paraList = paraList; 115 } 116 117 public void addPara(Para para) { 118 paraList.add(para); 119 } 120 121 public void removePara(Para para) { 122 paraList.remove(para); 123 } 124 125 public List getValidatorList() { 126 return validatorList; 127 } 128 129 public void setValidatorList(List validatorList) { 130 this.validatorList = validatorList; 131 } 132 133 public void addValidator(Validator validator) { 134 validatorList.add(validator); 135 } 136 137 public void removeValidator(Validator validator) { 138 validatorList.remove(validator); 139 } 140 141 public String getClassname() { 142 return classname; 143 } 144 145 public void setClassname(String classname) { 146 this.classname = classname; 147 zeus_ClassnameSet = true; 148 } 149 150 public void setDocType(String name, String publicID, String systemID) { 151 try { 152 startDTD(name, publicID, systemID); 153 } catch (SAXException neverHappens) { } 154 } 155 156 public void setOutputEncoding(String outputEncoding) { 157 this.outputEncoding = outputEncoding; 158 } 159 160 public void marshal(File file) throws IOException { 161 marshal(new FileWriter (file)); 163 } 164 165 public void marshal(OutputStream outputStream) throws IOException { 166 marshal(new OutputStreamWriter (outputStream)); 168 } 169 170 public void marshal(Writer writer) throws IOException { 171 writer.write("<?xml version=\"1.0\" "); 173 if (outputEncoding != null) { 174 writer.write("encoding=\""); 175 writer.write(outputEncoding); 176 writer.write("\"?>\n\n"); 177 178 } else { 179 writer.write("encoding=\"UTF-8\"?>\n\n"); 180 181 } 182 writer.write(docTypeString); 184 writer.write("\n"); 185 writeXMLRepresentation(writer, ""); 187 188 writer.flush(); 190 writer.close(); 191 } 192 193 protected void writeXMLRepresentation(Writer writer, 194 String indent) 195 throws IOException { 196 197 writer.write(indent); 198 writer.write("<validator"); 199 200 for (Iterator i = namespaceMappings.keySet().iterator(); i.hasNext(); ) { 202 String prefix = (String )i.next(); 203 String uri = (String )namespaceMappings.get(prefix); 204 writer.write(" xmlns"); 205 if (!prefix.trim().equals("")) { 206 writer.write(":"); 207 writer.write(prefix); 208 } 209 writer.write("=\""); 210 writer.write(uri); 211 writer.write("\"\n "); 212 } 213 214 if (zeus_ClassnameSet) { 216 writer.write(" classname=\""); 217 writer.write(escapeAttributeValue(classname)); 218 writer.write("\""); 219 } 220 writer.write(">"); 221 writer.write("\n"); 222 223 for (Iterator i=paraList.iterator(); i.hasNext(); ) { 225 ParaImpl para = (ParaImpl)i.next(); 226 para.writeXMLRepresentation(writer, 227 new StringBuffer (indent).append(" ").toString()); 228 } 229 for (Iterator i=validatorList.iterator(); i.hasNext(); ) { 230 ValidatorImpl validator = (ValidatorImpl)i.next(); 231 validator.writeXMLRepresentation(writer, 232 new StringBuffer (indent).append(" ").toString()); 233 } 234 writer.write(indent); 235 writer.write("</validator>\n"); 236 } 237 238 private String escapeAttributeValue(String attributeValue) { 239 String returnValue = attributeValue; 240 for (int i = 0; i < returnValue.length(); i++) { 241 char ch = returnValue.charAt(i); 242 if (ch == '"') { 243 returnValue = new StringBuffer () 244 .append(returnValue.substring(0, i)) 245 .append(""") 246 .append(returnValue.substring(i+1)) 247 .toString(); 248 } 249 } 250 return returnValue; 251 } 252 253 private String escapeTextValue(String textValue) { 254 String returnValue = textValue; 255 for (int i = 0; i < returnValue.length(); i++) { 256 char ch = returnValue.charAt(i); 257 if (ch == '<') { 258 returnValue = new StringBuffer () 259 .append(returnValue.substring(0, i)) 260 .append("<") 261 .append(returnValue.substring(i+1)) 262 .toString(); 263 } else if (ch == '>') { 264 returnValue = new StringBuffer () 265 .append(returnValue.substring(0, i)) 266 .append(">") 267 .append(returnValue.substring(i+1)) 268 .toString(); 269 } 270 } 271 return returnValue; 272 } 273 274 281 public static void setEntityResolver(EntityResolver resolver) { 282 entityResolver = resolver; 283 } 284 285 292 public static void setErrorHandler(ErrorHandler handler) { 293 errorHandler = handler; 294 } 295 296 public static Validator unmarshal(File file) throws IOException { 297 return unmarshal(new FileReader (file)); 299 } 300 301 public static Validator unmarshal(File file, boolean validate) throws IOException { 302 return unmarshal(new FileReader (file), validate); 304 } 305 306 public static Validator unmarshal(InputStream inputStream) throws IOException { 307 return unmarshal(new InputStreamReader (inputStream)); 309 } 310 311 public static Validator unmarshal(InputStream inputStream, boolean validate) throws IOException { 312 return unmarshal(new InputStreamReader (inputStream), validate); 314 } 315 316 public static Validator unmarshal(Reader reader) throws IOException { 317 return unmarshal(reader, false); 319 } 320 321 public static Validator unmarshal(Reader reader, boolean validate) throws IOException { 322 ValidatorImpl validator = ValidatorImpl.newInstance(); 323 validator.setValidating(validate); 324 validator.setCurrentUNode(validator); 325 validator.setParentUNode(null); 326 XMLReader parser = null; 328 String parserClass = System.getProperty("org.xml.sax.driver", 329 "org.apache.xerces.parsers.SAXParser"); 330 try { 331 parser = XMLReaderFactory.createXMLReader(parserClass); 332 333 if (entityResolver != null) { 335 parser.setEntityResolver(entityResolver); 336 } 337 338 parser.setErrorHandler(validator); 340 341 parser.setProperty("http://xml.org/sax/properties/lexical-handler", validator); 343 344 parser.setContentHandler(validator); 346 } catch (SAXException e) { 347 throw new IOException ("Could not load XML parser: " + 348 e.getMessage()); 349 } 350 351 InputSource inputSource = new InputSource (reader); 352 try { 353 parser.setFeature("http://xml.org/sax/features/validation", new Boolean (validate).booleanValue()); 354 parser.setFeature("http://xml.org/sax/features/namespaces", true); 355 parser.setFeature("http://xml.org/sax/features/namespace-prefixes", false); 356 parser.parse(inputSource); 357 } catch (SAXException e) { 358 throw new IOException ("Error parsing XML document: " + 359 e.getMessage()); 360 } 361 362 return validator; 364 } 365 366 public Unmarshallable getParentUNode() { 367 return zeus_parentUNode; 368 } 369 370 public void setParentUNode(Unmarshallable parentUNode) { 371 this.zeus_parentUNode = parentUNode; 372 } 373 374 public Unmarshallable getCurrentUNode() { 375 return zeus_currentUNode; 376 } 377 378 public void setCurrentUNode(Unmarshallable currentUNode) { 379 this.zeus_currentUNode = currentUNode; 380 } 381 382 public void setValidating(boolean validate) { 383 this.validate = validate; 384 } 385 386 public void startDocument() throws SAXException { 387 } 389 390 public void setDocumentLocator(Locator locator) { 391 } 393 394 public void startPrefixMapping(String prefix, String uri) 395 throws SAXException { 396 namespaceMappings.put(prefix, uri); 397 } 398 399 public void startElement(String namespaceURI, String localName, 400 String qName, org.xml.sax.Attributes atts) 401 throws SAXException { 402 403 Unmarshallable current = getCurrentUNode(); 405 if (current != this) { 406 current.startElement(namespaceURI, localName, qName, atts); 407 return; 408 } 409 410 if ((localName.equals("validator")) && (!zeus_thisNodeHandled)) { 412 for (int i=0, len=atts.getLength(); i<len; i++) { 414 String attName= atts.getLocalName(i); 415 String attValue = atts.getValue(i); 416 if (attName.equals("classname")) { 417 setClassname(attValue); 418 } 419 } 420 zeus_thisNodeHandled = true; 421 return; 422 } else { 423 if (localName.equals("para")) { 425 ParaImpl para = ParaImpl.newInstance(); 426 current = getCurrentUNode(); 427 para.setParentUNode(current); 428 para.setCurrentUNode(para); 429 this.setCurrentUNode(para); 430 para.startElement(namespaceURI, localName, qName, atts); 431 paraList.add(para); 433 return; 434 } 435 if (localName.equals("validator")) { 436 ValidatorImpl validator = ValidatorImpl.newInstance(); 437 current = getCurrentUNode(); 438 validator.setParentUNode(current); 439 validator.setCurrentUNode(validator); 440 this.setCurrentUNode(validator); 441 validator.startElement(namespaceURI, localName, qName, atts); 442 validatorList.add(validator); 444 return; 445 } 446 } 447 } 448 449 public void endElement(String namespaceURI, String localName, 450 String qName) 451 throws SAXException { 452 453 Unmarshallable current = getCurrentUNode(); 454 if (current != this) { 455 current.endElement(namespaceURI, localName, qName); 456 return; 457 } 458 459 Unmarshallable parent = getCurrentUNode().getParentUNode(); 460 if (parent != null) { 461 parent.setCurrentUNode(parent); 462 } 463 } 464 465 public void characters(char[] ch, int start, int len) 466 throws SAXException { 467 468 Unmarshallable current = getCurrentUNode(); 470 if (current != this) { 471 current.characters(ch, start, len); 472 return; 473 } 474 475 String text = new String (ch, start, len); 476 text = text.trim(); 477 } 478 479 public void comment(char ch[], int start, int len) throws SAXException { 480 } 482 483 public void warning(SAXParseException e) throws SAXException { 484 if (errorHandler != null) { 485 errorHandler.warning(e); 486 } 487 } 488 489 public void error(SAXParseException e) throws SAXException { 490 if ((validate) && (!hasDTD)) { 491 throw new SAXException ("Validation is turned on, but no DTD has been specified in the input XML document. Please supply a DTD through a DOCTYPE reference."); 492 } 493 if (errorHandler != null) { 494 errorHandler.error(e); 495 } 496 } 497 498 public void fatalError(SAXParseException e) throws SAXException { 499 if ((validate) && (!hasDTD)) { 500 throw new SAXException ("Validation is turned on, but no DTD has been specified in the input XML document. Please supply a DTD through a DOCTYPE reference."); 501 } 502 if (errorHandler != null) { 503 errorHandler.fatalError(e); 504 } 505 } 506 507 public void startDTD(String name, String publicID, String systemID) 508 throws SAXException { 509 510 if ((name == null) || (name.equals(""))) { 511 docTypeString = ""; 512 return; 513 } 514 515 hasDTD = true; 516 StringBuffer docTypeSB = new StringBuffer (); 517 boolean hasPublic = false; 518 519 docTypeSB.append("<!DOCTYPE ") 520 .append(name); 521 522 if ((publicID != null) && (!publicID.equals(""))) { 523 docTypeSB.append(" PUBLIC \"") 524 .append(publicID) 525 .append("\""); 526 hasPublic = true; 527 } 528 529 if ((systemID != null) && (!systemID.equals(""))) { 530 if (!hasPublic) { 531 docTypeSB.append(" SYSTEM"); 532 } 533 docTypeSB.append(" \"") 534 .append(systemID) 535 .append("\""); 536 537 } 538 539 docTypeSB.append(">"); 540 541 docTypeString = docTypeSB.toString(); 542 } 543 544 public void endDTD() throws SAXException { 545 } 547 548 public void startEntity(String name) throws SAXException { 549 } 551 552 public void endEntity(String name) throws SAXException { 553 } 555 556 public void startCDATA() throws SAXException { 557 } 559 560 public void endCDATA() throws SAXException { 561 } 563 564 } 565 | Popular Tags |