KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > lenya > xml > XPSAssembler


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */

17
18 /* $Id: XPSAssembler.java 42872 2004-04-20 13:37:02Z michi $ */
19
20 package org.apache.lenya.xml;
21
22
23 import java.io.File JavaDoc;
24 import java.io.FileOutputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.io.OutputStream JavaDoc;
28 import java.net.URL JavaDoc;
29 import java.util.Properties JavaDoc;
30 import java.util.StringTokenizer JavaDoc;
31 import java.util.Vector JavaDoc;
32
33 import org.apache.lenya.net.ProxyManager;
34 import org.apache.log4j.Category;
35 import org.w3c.dom.Document JavaDoc;
36 import org.w3c.dom.Element JavaDoc;
37 import org.w3c.dom.Node JavaDoc;
38 import org.w3c.dom.NodeList JavaDoc;
39
40
41 /**
42  * XLink/XInclude Processor (Nesting, Caching, Java, Exceptions)
43  */

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 JavaDoc XPSEXCEPTION_ELEMENT_NAME = "XPSEXCEPTION"; // better would be a namespace xps:XLinkException
51

52     /**
53      * Creates a new XPSAssembler object.
54      */

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 JavaDoc sp = System.getProperties();
63             sp.put("proxySet", "true");
64             sp.put("proxyHost", conf.proxyHost);
65             sp.put("proxyPort", conf.proxyPort);
66         }
67     }
68
69     /**
70      * Creates a new XPSAssembler object.
71      *
72      * @param includeoption DOCUMENT ME!
73      */

74     public XPSAssembler(String JavaDoc includeoption) {
75         this();
76         conf.INCLUDE = includeoption;
77     }
78
79     /**
80      * Usage of XPSAssembler
81      *
82      * @param args URI
83      */

84     public static void main(String JavaDoc[] 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 JavaDoc cocoon = null; // e.g. http://127.0.0.1:8080/lenya/nwt
97
Document JavaDoc document = xpsa.assemble(args[0], cocoon);
98
99         try {
100             OutputStream JavaDoc out = System.out;
101             new DOMWriter(out, "utf-8").printWithoutFormatting(document);
102
103             System.out.print("\n");
104             out.flush();
105         } catch (Exception JavaDoc e) {
106             System.err.println(xpsa.getClass().getName() + ".main(): " + e);
107         }
108     }
109
110     /**
111      * DOCUMENT ME!
112      *
113      * @param reference DOCUMENT ME!
114      * @param cocoon DOCUMENT ME!
115      *
116      * @return DOCUMENT ME!
117      */

118     public Document JavaDoc assemble(String JavaDoc reference, String JavaDoc cocoon) {
119         File JavaDoc workingDirectory = new File JavaDoc(System.getProperty("user.dir"));
120         XPSSourceInformation sourceInfo = new XPSSourceInformation("file:" + workingDirectory +
121                 "/dummy.xml", cocoon);
122         String JavaDoc[] args = new String JavaDoc[1];
123         args[0] = reference;
124
125         XPSSourceInformation currentInfo = new XPSSourceInformation(args[0], sourceInfo, cocoon);
126         deleteFromCache(currentInfo.url);
127
128         Vector JavaDoc nodes = include(args, sourceInfo);
129         log.debug(sourceInfo);
130
131         Node JavaDoc node = (Node JavaDoc) nodes.elementAt(0);
132
133         return node.getOwnerDocument();
134     }
135
136     /**
137      * Remove file from cache
138      *
139      * @param url DOCUMENT ME!
140      */

141     public void deleteFromCache(URL JavaDoc url) {
142         if (conf.cacheFolder != null) {
143             File JavaDoc 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     /**
156      * DOCUMENT ME!
157      *
158      * @param document DOCUMENT ME!
159      * @param reference DOCUMENT ME!
160      * @param cocoon DOCUMENT ME!
161      *
162      * @return DOCUMENT ME!
163      */

164     public Document JavaDoc assemble(Document JavaDoc document, String JavaDoc reference, String JavaDoc cocoon) {
165         //return document;
166
Element JavaDoc root = document.getDocumentElement();
167         Document JavaDoc assembledDocument = dpf.getDocument();
168         Element JavaDoc assembledRoot = (Element JavaDoc) dpf.cloneNode(assembledDocument, root, false);
169         assembledDocument.appendChild(assembledRoot);
170
171         File JavaDoc workingDirectory = new File JavaDoc(System.getProperty("user.dir"));
172         XPSSourceInformation sourceInfo = new XPSSourceInformation("file:" + workingDirectory + "/dummy.xml", cocoon);
173         XPSSourceInformation currentInfo = new XPSSourceInformation(reference, sourceInfo, cocoon);
174         NodeList JavaDoc 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     /**
184      * DOCUMENT ME!
185      *
186      * @param currentInfo DOCUMENT ME!
187      *
188      * @return DOCUMENT ME!
189      *
190      * @throws Exception DOCUMENT ME!
191      */

192     public InputStream JavaDoc readXML(XPSSourceInformation currentInfo)
193         throws Exception JavaDoc {
194         InputStream JavaDoc is = null;
195         File JavaDoc cacheFile = null;
196         long originalFileLastModified = 0;
197
198         String JavaDoc protocol = currentInfo.url.getProtocol();
199
200         URL JavaDoc url = null;
201
202         if (conf.cacheFolder != null) // Check cache
203
{
204             cacheFile = getCacheFile(currentInfo.url);
205
206             if (protocol.equals("file")) {
207                 File JavaDoc originalFile = new File JavaDoc(currentInfo.url.getFile());
208                 originalFileLastModified = originalFile.lastModified();
209             } else if (protocol.equals("http")) {
210                 pm.set(currentInfo.url.getHost()); // install proxy if necessary
211
originalFileLastModified = currentInfo.url.openConnection().getLastModified();
212             } else {
213                 log.error("No such protocol: " + protocol);
214             }
215
216             if (cacheFile.isFile() && (cacheFile.lastModified() >= originalFileLastModified)) {
217                 // File already exists in cache and is newer than original File
218
url = new URL JavaDoc("file:" + cacheFile.getAbsolutePath());
219             } else { // File does not exist in cache
220
url = new URL JavaDoc(currentInfo.url.toString());
221             }
222         } else { // No cache folder specified
223
url = new URL JavaDoc(currentInfo.url.toString());
224         }
225
226         // Read Document
227
is = url.openStream();
228
229         return is;
230     }
231
232     /**
233      * DOCUMENT ME!
234      *
235      * @param currentInfo DOCUMENT ME!
236      * @param newDocument DOCUMENT ME!
237      *
238      * @return DOCUMENT ME!
239      */

240     public boolean tryWritingToCache(XPSSourceInformation currentInfo, Document JavaDoc newDocument) {
241         File JavaDoc cacheFile = null;
242
243         if (conf.cacheFolder != null) // Check cache
244
{
245             cacheFile = getCacheFile(currentInfo.url);
246         }
247
248         if (cacheFile != null) {
249             String JavaDoc protocol = currentInfo.url.getProtocol();
250
251             if (!cacheFile.exists()) { // Write "Xlink" to cache
252

253                 return writeToCache(protocol, cacheFile, newDocument);
254             } else { // cacheFile exists
255

256                 long originalFileLastModified = 0;
257                 String JavaDoc p = currentInfo.url.getProtocol();
258
259                 if (p.equals("file")) {
260                     File JavaDoc originalFile = new File JavaDoc(currentInfo.url.getFile());
261                     originalFileLastModified = originalFile.lastModified();
262                 } else if (p.equals("http")) {
263                     try {
264                         originalFileLastModified = currentInfo.url.openConnection().getLastModified();
265                     } catch (IOException JavaDoc e) {
266                         log.error("originalFileLastModified: " + e);
267                     }
268                 } else {
269                     log.error("No such protocol: " + p);
270                 }
271
272                 if (cacheFile.lastModified() < originalFileLastModified) {
273                     // File in cache is older than original File
274
return writeToCache(protocol, cacheFile, newDocument);
275                 }
276             }
277         }
278
279         return false;
280     }
281
282     /**
283      * param args args[0]=url
284      *
285      * @param args DOCUMENT ME!
286      * @param sourceInfo DOCUMENT ME!
287      *
288      * @return DOCUMENT ME!
289      */

290     public Vector JavaDoc include(String JavaDoc[] 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 JavaDoc document = null;
301         Vector JavaDoc nodes = new Vector JavaDoc();
302         Document JavaDoc newDocument = dpf.getDocument();
303
304         try {
305             InputStream JavaDoc is = readXML(currentInfo);
306             document = dpf.getDocument(is);
307         } catch (Exception JavaDoc e) {
308             log.warn(e + ", currentInfo: " + currentInfo.url.getFile() + " , sourceInfo: " + sourceInfo.url.getFile());
309
310             Element JavaDoc 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 JavaDoc root = document.getDocumentElement();
318         Element JavaDoc newRoot = (Element JavaDoc) dpf.cloneNode(newDocument, root, false);
319         newDocument.appendChild(newRoot);
320
321         NodeList JavaDoc 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 JavaDoc) nodes.elementAt(i)).getNodeType();
339
340                     switch (nodeType) {
341                     case Node.ELEMENT_NODE:
342                         break;
343
344                     case Node.ATTRIBUTE_NODE: {
345                         Node JavaDoc attribute = (Node JavaDoc) 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 JavaDoc e) {
362                 log.error("", e);
363             }
364         }
365
366         return nodes;
367     }
368
369     /**
370      * Traverses recursively and looks for XLinks and includes the returned NodeList
371      *
372      * @param newParent DOCUMENT ME!
373      * @param orgChild DOCUMENT ME!
374      * @param sourceInfo DOCUMENT ME!
375      * @param currentInfo DOCUMENT ME!
376      */

377     public void traverse(Node JavaDoc newParent, Node JavaDoc orgChild, XPSSourceInformation sourceInfo,
378         XPSSourceInformation currentInfo) {
379         Vector JavaDoc newChildren = new Vector JavaDoc();
380         short nodeType = orgChild.getNodeType();
381         boolean noXLink = true;
382
383         switch (nodeType) {
384         case Node.ELEMENT_NODE: {
385             XLink xlink = new XLink((Element JavaDoc) orgChild);
386
387             if (xlink.href == null) {
388                 Element JavaDoc newElement = (Element JavaDoc) 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 JavaDoc nl = processXLink(xlink, (Element JavaDoc) 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 JavaDoc) newChildren.elementAt(i));
430         }
431
432         if (orgChild.hasChildNodes() && noXLink) {
433             NodeList JavaDoc nl = orgChild.getChildNodes();
434
435             for (int i = 0; i < nl.getLength(); i++) {
436                 traverse((Node JavaDoc) newChildren.elementAt(0), nl.item(i), sourceInfo, currentInfo);
437             }
438         }
439     }
440
441     /**
442      * Process XLink
443      *
444      * @param xlink DOCUMENT ME!
445      * @param orgChild DOCUMENT ME!
446      * @param currentInfo DOCUMENT ME!
447      *
448      * @return DOCUMENT ME!
449      */

450     public NodeList JavaDoc processXLink(XLink xlink, Element JavaDoc orgChild, XPSSourceInformation currentInfo) {
451         NodeList JavaDoc nl = null;
452
453         // NOTE: if no show attribute is specified, then the value will be set to "undefined"
454
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 JavaDoc args = new Vector JavaDoc();
459             String JavaDoc includeClassName = includeClassName(xlink.href, args);
460             String JavaDoc[] arguments = new String JavaDoc[args.size()];
461
462             for (int i = 0; i < args.size(); i++) {
463                 arguments[i] = (String JavaDoc) args.elementAt(i);
464                 log.debug("Arguments: " + arguments[i]);
465             }
466
467             Vector JavaDoc newChildren = null;
468
469             try {
470                 if (includeClassName.equals(this.getClass().getName())) {
471                     newChildren = include(arguments, currentInfo);
472                 } else {
473                     Class JavaDoc includeClass = Class.forName(includeClassName);
474                     XPSInclude xpsInclude = (XPSInclude) includeClass.newInstance();
475                     newChildren = xpsInclude.include(arguments, currentInfo);
476                 }
477             } catch (Exception JavaDoc e) {
478                 log.error(".processXLink(): " + e);
479             }
480
481             if (newChildren != null) // Returned nodes from XLink
482
{
483                 if (newChildren.size() > 0) {
484                     Node JavaDoc firstChild = (Node JavaDoc) newChildren.elementAt(0);
485                     Document JavaDoc xlinkedDocument = firstChild.getOwnerDocument();
486                     Element JavaDoc dummyRoot = dpf.newElementNode(xlinkedDocument, "DummyRoot");
487
488                     if (xlink.show.equals("embed")) {
489                     //if (conf.INCLUDE.equals("embed")) {
490
// WARNING: embed was actually meant to also include the actual xlink, but
491
// it was never really implemented and hence led to the misinterpretation of replace
492
// Therefore we treat it the same as replace
493
//dummyRoot.appendChild(xlink.getXLink(xlinkedDocument, dpf));
494

495                         for (int i = 0; i < newChildren.size(); i++) {
496                             dummyRoot.appendChild((Node JavaDoc) newChildren.elementAt(i));
497                         }
498             } else if (xlink.show.equals("replace")) {
499             //} else if (conf.INCLUDE.equals("replace")) {
500
for (int i = 0; i < newChildren.size(); i++) {
501                             dummyRoot.appendChild((Node JavaDoc) newChildren.elementAt(i));
502                         }
503                     } else if (xlink.show.equals("enclose")) {
504                     //} else if (conf.INCLUDE.equals("enclose")) {
505
Element JavaDoc xlinkCopy = xlink.getXLink(xlinkedDocument, dpf);
506
507                         for (int i = 0; i < newChildren.size(); i++) {
508                             xlinkCopy.appendChild((Node JavaDoc) 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     /**
532      * DOCUMENT ME!
533      *
534      * @param xlink DOCUMENT ME!
535      *
536      * @return DOCUMENT ME!
537      */

538     public NodeList JavaDoc noNodesReturnedFromXLink(XLink xlink) {
539         log.warn("No nodes returned from XLink: " + xlink);
540
541         Document JavaDoc dummyDocument = dpf.getDocument();
542         Element JavaDoc dummyRoot = dpf.newElementNode(dummyDocument, "DummyRoot");
543         Element JavaDoc element = xlink.getXLink(dummyDocument, dpf);
544         dummyRoot.appendChild(element);
545
546         Element JavaDoc 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     /**
554      * DOCUMENT ME!
555      *
556      * @param href DOCUMENT ME!
557      * @param args DOCUMENT ME!
558      *
559      * @return DOCUMENT ME!
560      */

561     public String JavaDoc includeClassName(String JavaDoc href, Vector JavaDoc args) {
562         String JavaDoc 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 JavaDoc st = new StringTokenizer JavaDoc(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     /**
585      * DOCUMENT ME!
586      *
587      * @param url DOCUMENT ME!
588      *
589      * @return DOCUMENT ME!
590      */

591     public File JavaDoc getCacheFile(URL JavaDoc url) {
592         String JavaDoc cacheFile = null;
593         String JavaDoc 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 JavaDoc(conf.cacheFolder + "/" + cacheFile);
604     }
605
606     /**
607      *
608      */

609     public boolean writeToCache(String JavaDoc protocol, File JavaDoc cacheFile, Document JavaDoc newDocument) {
610         if (protocol.equals("http") && !conf.cacheHTTP) {
611             // Do not cache HTTP
612
return false;
613         }
614
615         File JavaDoc cacheFileParent = new File JavaDoc(cacheFile.getParent());
616
617         if (!cacheFileParent.isDirectory()) {
618             cacheFileParent.mkdirs();
619         }
620
621         try {
622             OutputStream JavaDoc out = new FileOutputStream JavaDoc(cacheFile.getAbsolutePath());
623
624             new DOMWriter(out, "iso-8859-1").printWithoutFormatting(newDocument);
625             out.close();
626
627             return true;
628         } catch (Exception JavaDoc e) {
629             log.error(".include(): " + e);
630         }
631
632         return false;
633     }
634 }
635
Popular Tags