1 17 18 19 20 package org.apache.lenya.xml; 21 22 23 import java.io.File ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.OutputStream ; 28 import java.net.URL ; 29 import java.util.Properties ; 30 import java.util.StringTokenizer ; 31 import java.util.Vector ; 32 33 import org.apache.lenya.net.ProxyManager; 34 import org.apache.log4j.Category; 35 import org.w3c.dom.Document ; 36 import org.w3c.dom.Element ; 37 import org.w3c.dom.Node ; 38 import org.w3c.dom.NodeList ; 39 40 41 44 public class XPSAssembler implements XPSInclude { 45 static Category log = Category.getInstance(XPSAssembler.class); 46 DOMParserFactory dpf = null; 47 XPointerFactory xpf = null; 48 Configuration conf = null; 49 ProxyManager pm = null; 50 String XPSEXCEPTION_ELEMENT_NAME = "XPSEXCEPTION"; 52 55 public XPSAssembler() { 56 dpf = new DOMParserFactory(); 57 xpf = new XPointerFactory(); 58 conf = new Configuration(); 59 pm = new ProxyManager(); 60 61 if ((conf.proxyHost != null) && (conf.proxyPort != null)) { 62 Properties sp = System.getProperties(); 63 sp.put("proxySet", "true"); 64 sp.put("proxyHost", conf.proxyHost); 65 sp.put("proxyPort", conf.proxyPort); 66 } 67 } 68 69 74 public XPSAssembler(String includeoption) { 75 this(); 76 conf.INCLUDE = includeoption; 77 } 78 79 84 public static void main(String [] args) { 85 XPSAssembler xpsa = new XPSAssembler(); 86 87 if (args.length != 1) { 88 System.err.println("Usage:"); 89 System.err.println(" java " + xpsa.getClass().getName() + " \"../x/xps/samples/tbs/xml/invoices/invoice.xml\""); 90 System.err.println(" java " + xpsa.getClass().getName() + " \"file:/...\""); 91 System.err.println(" java " + xpsa.getClass().getName() + " \"http://localhost/...\""); 92 93 return; 94 } 95 96 String cocoon = null; Document document = xpsa.assemble(args[0], cocoon); 98 99 try { 100 OutputStream out = System.out; 101 new DOMWriter(out, "utf-8").printWithoutFormatting(document); 102 103 System.out.print("\n"); 104 out.flush(); 105 } catch (Exception e) { 106 System.err.println(xpsa.getClass().getName() + ".main(): " + e); 107 } 108 } 109 110 118 public Document assemble(String reference, String cocoon) { 119 File workingDirectory = new File (System.getProperty("user.dir")); 120 XPSSourceInformation sourceInfo = new XPSSourceInformation("file:" + workingDirectory + 121 "/dummy.xml", cocoon); 122 String [] args = new String [1]; 123 args[0] = reference; 124 125 XPSSourceInformation currentInfo = new XPSSourceInformation(args[0], sourceInfo, cocoon); 126 deleteFromCache(currentInfo.url); 127 128 Vector nodes = include(args, sourceInfo); 129 log.debug(sourceInfo); 130 131 Node node = (Node ) nodes.elementAt(0); 132 133 return node.getOwnerDocument(); 134 } 135 136 141 public void deleteFromCache(URL url) { 142 if (conf.cacheFolder != null) { 143 File cacheFile = getCacheFile(url); 144 145 if (cacheFile.isFile()) { 146 log.info(".deleteFromCache(): " + cacheFile.getAbsolutePath()); 147 cacheFile.delete(); 148 } else { 149 log.warn(".deleteFromCache(): No such file in cache: " + 150 cacheFile.getAbsolutePath()); 151 } 152 } 153 } 154 155 164 public Document assemble(Document document, String reference, String cocoon) { 165 Element root = document.getDocumentElement(); 167 Document assembledDocument = dpf.getDocument(); 168 Element assembledRoot = (Element ) dpf.cloneNode(assembledDocument, root, false); 169 assembledDocument.appendChild(assembledRoot); 170 171 File workingDirectory = new File (System.getProperty("user.dir")); 172 XPSSourceInformation sourceInfo = new XPSSourceInformation("file:" + workingDirectory + "/dummy.xml", cocoon); 173 XPSSourceInformation currentInfo = new XPSSourceInformation(reference, sourceInfo, cocoon); 174 NodeList nl = root.getChildNodes(); 175 176 for (int i = 0; i < nl.getLength(); i++) { 177 traverse(assembledRoot, nl.item(i), sourceInfo, currentInfo); 178 } 179 180 return assembledDocument; 181 } 182 183 192 public InputStream readXML(XPSSourceInformation currentInfo) 193 throws Exception { 194 InputStream is = null; 195 File cacheFile = null; 196 long originalFileLastModified = 0; 197 198 String protocol = currentInfo.url.getProtocol(); 199 200 URL url = null; 201 202 if (conf.cacheFolder != null) { 204 cacheFile = getCacheFile(currentInfo.url); 205 206 if (protocol.equals("file")) { 207 File originalFile = new File (currentInfo.url.getFile()); 208 originalFileLastModified = originalFile.lastModified(); 209 } else if (protocol.equals("http")) { 210 pm.set(currentInfo.url.getHost()); originalFileLastModified = currentInfo.url.openConnection().getLastModified(); 212 } else { 213 log.error("No such protocol: " + protocol); 214 } 215 216 if (cacheFile.isFile() && (cacheFile.lastModified() >= originalFileLastModified)) { 217 url = new URL ("file:" + cacheFile.getAbsolutePath()); 219 } else { url = new URL (currentInfo.url.toString()); 221 } 222 } else { url = new URL (currentInfo.url.toString()); 224 } 225 226 is = url.openStream(); 228 229 return is; 230 } 231 232 240 public boolean tryWritingToCache(XPSSourceInformation currentInfo, Document newDocument) { 241 File cacheFile = null; 242 243 if (conf.cacheFolder != null) { 245 cacheFile = getCacheFile(currentInfo.url); 246 } 247 248 if (cacheFile != null) { 249 String protocol = currentInfo.url.getProtocol(); 250 251 if (!cacheFile.exists()) { 253 return writeToCache(protocol, cacheFile, newDocument); 254 } else { 256 long originalFileLastModified = 0; 257 String p = currentInfo.url.getProtocol(); 258 259 if (p.equals("file")) { 260 File originalFile = new File (currentInfo.url.getFile()); 261 originalFileLastModified = originalFile.lastModified(); 262 } else if (p.equals("http")) { 263 try { 264 originalFileLastModified = currentInfo.url.openConnection().getLastModified(); 265 } catch (IOException e) { 266 log.error("originalFileLastModified: " + e); 267 } 268 } else { 269 log.error("No such protocol: " + p); 270 } 271 272 if (cacheFile.lastModified() < originalFileLastModified) { 273 return writeToCache(protocol, cacheFile, newDocument); 275 } 276 } 277 } 278 279 return false; 280 } 281 282 290 public Vector include(String [] args, XPSSourceInformation sourceInfo) { 291 XPSSourceInformation currentInfo = new XPSSourceInformation(args[0], sourceInfo, sourceInfo.cocoon); 292 293 sourceInfo.addChild(currentInfo); 294 295 if (currentInfo.checkLoop(sourceInfo, currentInfo.url)) { 296 log.warn("Loop detected: " + sourceInfo.url.getFile() + " " + currentInfo.url.getFile()); 297 return null; 298 } 299 300 Document document = null; 301 Vector nodes = new Vector (); 302 Document newDocument = dpf.getDocument(); 303 304 try { 305 InputStream is = readXML(currentInfo); 306 document = dpf.getDocument(is); 307 } catch (Exception e) { 308 log.warn(e + ", currentInfo: " + currentInfo.url.getFile() + " , sourceInfo: " + sourceInfo.url.getFile()); 309 310 Element newRoot = dpf.newElementNode(newDocument, XPSEXCEPTION_ELEMENT_NAME); 311 newRoot.appendChild(dpf.newTextNode(newDocument, "" + e)); 312 nodes.addElement(newRoot); 313 314 return nodes; 315 } 316 317 Element root = document.getDocumentElement(); 318 Element newRoot = (Element ) dpf.cloneNode(newDocument, root, false); 319 newDocument.appendChild(newRoot); 320 321 NodeList nl = root.getChildNodes(); 322 323 for (int i = 0; i < nl.getLength(); i++) { 324 traverse(newRoot, nl.item(i), sourceInfo, currentInfo); 325 } 326 327 boolean writtenToCache = tryWritingToCache(currentInfo, newDocument); 328 329 if (currentInfo.url.getRef() == null) { 330 log.debug("No XPointer. Return the root node in order to add the whole document."); 331 nodes.addElement(newRoot); 332 } else { 333 log.debug("XPointer: " + currentInfo.url.getRef()); 334 try { 335 nodes = xpf.select(newRoot, currentInfo.url.getRef()); 336 337 for (int i = 0; i < nodes.size(); i++) { 338 short nodeType = ((Node ) nodes.elementAt(i)).getNodeType(); 339 340 switch (nodeType) { 341 case Node.ELEMENT_NODE: 342 break; 343 344 case Node.ATTRIBUTE_NODE: { 345 Node attribute = (Node ) nodes.elementAt(i); 346 nodes.removeElementAt(i); 347 nodes.insertElementAt(dpf.newTextNode(attribute.getOwnerDocument(), 348 attribute.getNodeValue()), i); 349 350 break; 351 } 352 353 default: { 354 log.error(".include(): Node Type (" + nodeType + ") can't be a child of Element"); 355 nodes.removeElementAt(i); 356 357 break; 358 } 359 } 360 } 361 } catch (Exception e) { 362 log.error("", e); 363 } 364 } 365 366 return nodes; 367 } 368 369 377 public void traverse(Node newParent, Node orgChild, XPSSourceInformation sourceInfo, 378 XPSSourceInformation currentInfo) { 379 Vector newChildren = new Vector (); 380 short nodeType = orgChild.getNodeType(); 381 boolean noXLink = true; 382 383 switch (nodeType) { 384 case Node.ELEMENT_NODE: { 385 XLink xlink = new XLink((Element ) orgChild); 386 387 if (xlink.href == null) { 388 Element newElement = (Element ) dpf.cloneNode(newParent.getOwnerDocument(), orgChild, false); 389 newChildren.addElement(newElement); 390 } else { 391 noXLink = false; 392 log.debug(".traverse(): xlink:href=\"" + xlink.href + "\""); 393 394 NodeList nl = processXLink(xlink, (Element ) orgChild, currentInfo); 395 396 for (int i = 0; i < nl.getLength(); i++) { 397 newChildren.addElement(dpf.cloneNode(newParent.getOwnerDocument(), nl.item(i), true)); 398 } 399 } 400 401 break; 402 } 403 404 case Node.COMMENT_NODE: { 405 newChildren.addElement(dpf.newCommentNode(newParent.getOwnerDocument(), orgChild.getNodeValue())); 406 407 break; 408 } 409 410 case Node.TEXT_NODE: { 411 newChildren.addElement(dpf.newTextNode(newParent.getOwnerDocument(), orgChild.getNodeValue())); 412 413 break; 414 } 415 416 case Node.CDATA_SECTION_NODE: { 417 newChildren.addElement(dpf.newCDATASection(newParent.getOwnerDocument(), orgChild.getNodeValue())); 418 419 break; 420 } 421 422 default: { 423 log.error(".traverse(): Node type not implemented: " + nodeType + " (" + currentInfo.url + ")"); 424 break; 425 } 426 } 427 428 for (int i = 0; i < newChildren.size(); i++) { 429 newParent.appendChild((Node ) newChildren.elementAt(i)); 430 } 431 432 if (orgChild.hasChildNodes() && noXLink) { 433 NodeList nl = orgChild.getChildNodes(); 434 435 for (int i = 0; i < nl.getLength(); i++) { 436 traverse((Node ) newChildren.elementAt(0), nl.item(i), sourceInfo, currentInfo); 437 } 438 } 439 } 440 441 450 public NodeList processXLink(XLink xlink, Element orgChild, XPSSourceInformation currentInfo) { 451 NodeList nl = null; 452 453 if (!(xlink.show.equals("embed") || xlink.show.equals("enclose") || xlink.show.equals("replace"))) { 455 log.warn("No such value of attribute \"show\" implemented: " + xlink.show); 456 nl = noNodesReturnedFromXLink(xlink); 457 } else { 458 Vector args = new Vector (); 459 String includeClassName = includeClassName(xlink.href, args); 460 String [] arguments = new String [args.size()]; 461 462 for (int i = 0; i < args.size(); i++) { 463 arguments[i] = (String ) args.elementAt(i); 464 log.debug("Arguments: " + arguments[i]); 465 } 466 467 Vector newChildren = null; 468 469 try { 470 if (includeClassName.equals(this.getClass().getName())) { 471 newChildren = include(arguments, currentInfo); 472 } else { 473 Class includeClass = Class.forName(includeClassName); 474 XPSInclude xpsInclude = (XPSInclude) includeClass.newInstance(); 475 newChildren = xpsInclude.include(arguments, currentInfo); 476 } 477 } catch (Exception e) { 478 log.error(".processXLink(): " + e); 479 } 480 481 if (newChildren != null) { 483 if (newChildren.size() > 0) { 484 Node firstChild = (Node ) newChildren.elementAt(0); 485 Document xlinkedDocument = firstChild.getOwnerDocument(); 486 Element dummyRoot = dpf.newElementNode(xlinkedDocument, "DummyRoot"); 487 488 if (xlink.show.equals("embed")) { 489 495 for (int i = 0; i < newChildren.size(); i++) { 496 dummyRoot.appendChild((Node ) newChildren.elementAt(i)); 497 } 498 } else if (xlink.show.equals("replace")) { 499 for (int i = 0; i < newChildren.size(); i++) { 501 dummyRoot.appendChild((Node ) newChildren.elementAt(i)); 502 } 503 } else if (xlink.show.equals("enclose")) { 504 Element xlinkCopy = xlink.getXLink(xlinkedDocument, dpf); 506 507 for (int i = 0; i < newChildren.size(); i++) { 508 xlinkCopy.appendChild((Node ) newChildren.elementAt(i)); 509 } 510 dummyRoot.appendChild(xlinkCopy); 511 } else { 512 log.warn("No such attribute \"show\" or such value of attribute \"show\" implemented"); 513 } 514 515 nl = dummyRoot.getChildNodes(); 516 } 517 } 518 519 if (nl == null) { 520 nl = noNodesReturnedFromXLink(xlink); 521 } 522 523 if (nl.getLength() == 0) { 524 nl = noNodesReturnedFromXLink(xlink); 525 } 526 } 527 528 return nl; 529 } 530 531 538 public NodeList noNodesReturnedFromXLink(XLink xlink) { 539 log.warn("No nodes returned from XLink: " + xlink); 540 541 Document dummyDocument = dpf.getDocument(); 542 Element dummyRoot = dpf.newElementNode(dummyDocument, "DummyRoot"); 543 Element element = xlink.getXLink(dummyDocument, dpf); 544 dummyRoot.appendChild(element); 545 546 Element exceptionElement = dpf.newElementNode(dummyDocument, XPSEXCEPTION_ELEMENT_NAME); 547 exceptionElement.appendChild(dpf.newElementNode(dummyDocument, "NoNodesReturnedFromXLink")); 548 dummyRoot.appendChild(exceptionElement); 549 550 return dummyRoot.getChildNodes(); 551 } 552 553 561 public String includeClassName(String href, Vector args) { 562 String icn = null; 563 564 if (href.indexOf(conf.JAVA_ZONE) == 0) { 565 log.debug(".includeClassName(): java class: " + href); 566 icn = href.substring(conf.JAVA_ZONE.length(), href.length()); 567 568 StringTokenizer st = new StringTokenizer (icn, "?"); 569 icn = st.nextToken(); 570 571 if (st.countTokens() == 1) { 572 args.addElement(st.nextToken()); 573 } 574 } else { 575 icn = this.getClass().getName(); 576 args.addElement(href); 577 } 578 579 log.debug(".includeClassName(): class name: " + icn); 580 581 return icn; 582 } 583 584 591 public File getCacheFile(URL url) { 592 String cacheFile = null; 593 String protocol = url.getProtocol(); 594 595 if (protocol.equals("file")) { 596 cacheFile = protocol + "/" + url.getFile(); 597 } else if (protocol.equals("http")) { 598 cacheFile = protocol + "/" + url.getHost() + "/" + url.getPort() + "/" + url.getFile(); 599 } else { 600 log.error("No such protocol: " + protocol); 601 } 602 603 return new File (conf.cacheFolder + "/" + cacheFile); 604 } 605 606 609 public boolean writeToCache(String protocol, File cacheFile, Document newDocument) { 610 if (protocol.equals("http") && !conf.cacheHTTP) { 611 return false; 613 } 614 615 File cacheFileParent = new File (cacheFile.getParent()); 616 617 if (!cacheFileParent.isDirectory()) { 618 cacheFileParent.mkdirs(); 619 } 620 621 try { 622 OutputStream out = new FileOutputStream (cacheFile.getAbsolutePath()); 623 624 new DOMWriter(out, "iso-8859-1").printWithoutFormatting(newDocument); 625 out.close(); 626 627 return true; 628 } catch (Exception e) { 629 log.error(".include(): " + e); 630 } 631 632 return false; 633 } 634 } 635 | Popular Tags |