1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package org.openoffice.xmerge.converter.dom;
25 
26 import java.io.InputStream;
27 import java.io.OutputStream;
28 import java.io.StringWriter;
29 import java.io.ByteArrayOutputStream;
30 import java.io.IOException;
31 
32 
33 import javax.xml.parsers.DocumentBuilderFactory;
34 import javax.xml.parsers.DocumentBuilder;
35 import javax.xml.parsers.ParserConfigurationException;
36 
37 import javax.xml.transform.TransformerFactory;
38 import javax.xml.transform.Transformer;
39 import javax.xml.transform.stream.StreamResult;
40 import javax.xml.transform.dom.DOMSource;
41 
42 import org.w3c.dom.Node;
43 import org.w3c.dom.Element;
44 import org.w3c.dom.Document;
45 import org.xml.sax.SAXException;
46 
47 import org.openoffice.xmerge.util.Resources;
48 import org.openoffice.xmerge.util.Debug;
49 
50 /**
51  *  An implementation of <code>Document</code> for
52  *  StarOffice documents.
53  */
54 public class DOMDocument
55     implements org.openoffice.xmerge.Document {
56 
57     /** Factory for <code>DocumentBuilder</code> objects. */
58     private static DocumentBuilderFactory factory =
59        DocumentBuilderFactory.newInstance();
60 
61     /** DOM <code>Document</code> of content.xml. */
62     private Document contentDoc = null;
63 
64     private String documentName = null;
65     private String fileName = null;
66     private String fileExt = null;
67 
68     /** Resources object. */
69     private Resources res = null;
70 
71 
72     /**
73      *  Default constructor.
74      *
75      *  @param  name  <code>Document</code> name.
76      *  @param  ext   <code>Document</code> extension.
77      */
DOMDocument(String name,String ext)78     public DOMDocument(String name,String ext)
79     {
80 	this(name,ext,true, false);
81     }
82 
83      /**
84      *  Returns the file extension of the <code>Document</code>
85      *  represented.
86      *
87      *  @return  file extension of the <code>Document</code>.
88      */
getFileExtension()89     protected String getFileExtension() {
90         return fileExt;
91     }
92 
93 
94     /**
95      *  Constructor with arguments to set <code>namespaceAware</code>
96      *  and <code>validating</code> flags.
97      *
98      *  @param  name            <code>Document</code> name (may or may not
99      *                          contain extension).
100      *  @param  ext             <code>Document</code> extension.
101      *  @param  namespaceAware  Value for <code>namespaceAware</code> flag.
102      *  @param  validating      Value for <code>validating</code> flag.
103      */
DOMDocument(String name, String ext,boolean namespaceAware, boolean validating)104     public DOMDocument(String name, String ext,boolean namespaceAware, boolean validating) {
105 
106         res = Resources.getInstance();
107         factory.setValidating(validating);
108         factory.setNamespaceAware(namespaceAware);
109         this.fileExt = ext;
110 	this.documentName = trimDocumentName(name);
111         this.fileName = documentName + getFileExtension();
112     }
113 
114 
115     /**
116      *  Removes the file extension from the <code>Document</code>
117      *  name.
118      *
119      *  @param  name  Full <code>Document</code> name with extension.
120      *
121      *  @return  Name of <code>Document</code> without the extension.
122      */
trimDocumentName(String name)123     private String trimDocumentName(String name) {
124         String temp = name.toLowerCase();
125         String ext = getFileExtension();
126 
127         if (temp.endsWith(ext)) {
128             // strip the extension
129             int nlen = name.length();
130             int endIndex = nlen - ext.length();
131             name = name.substring(0,endIndex);
132         }
133 
134         return name;
135     }
136 
137 
138     /**
139      *  Return a DOM <code>Document</code> object of the document content
140      *  file.  Note that a content DOM is not created when the constructor
141      *  is called.  So, either the <code>read</code> method or the
142      *  <code>initContentDOM</code> method will need to be called ahead
143      *  on this object before calling this method.
144      *
145      *  @return  DOM <code>Document</code> object.
146      */
getContentDOM()147     public Document getContentDOM() {
148 
149         return contentDoc;
150     }
151 
152     /**
153      *  Sets the Content of the <code>Document</code> to the contents of the
154      *  supplied <code>Node</code> list.
155      *
156      *  @return  DOM <code>Document</code> object.
157      */
setContentDOM( Node newDom)158     public void setContentDOM( Node newDom) {
159 	contentDoc=(Document)newDom;
160     }
161 
162 
163     /**
164      *  Return the name of the <code>Document</code>.
165      *
166      *  @return  The name of <code>Document</code>.
167      */
getName()168     public String getName() {
169 
170         return documentName;
171     }
172 
173 
174     /**
175      *  Return the file name of the <code>Document</code>, possibly
176      *  with the standard extension.
177      *
178      *  @return  The file name of <code>Document</code>.
179      */
getFileName()180     public String getFileName() {
181 
182         return fileName;
183     }
184 
185 
186     /**
187      *  Read the Office <code>Document</code> from the specified
188      *  <code>InputStream</code>.
189      *
190      *  @param  is  Office document <code>InputStream</code>.
191      *
192      *  @throws  IOException  If any I/O error occurs.
193      */
read(InputStream is)194     public void read(InputStream is) throws IOException {
195 	 Debug.log(Debug.INFO, "reading file");
196         DocumentBuilder builder = null;
197         try {
198             builder = factory.newDocumentBuilder();
199         } catch (ParserConfigurationException ex) {
200 	    System.out.println("Error:"+ ex);
201             //throw new OfficeDocumentException(ex);
202         }
203 	try {
204 
205 	    contentDoc=  builder.parse(is);
206 
207 
208         } catch (SAXException ex) {
209 	    System.out.println("Error:"+ ex);
210             //throw new OfficeDocumentException(ex);
211         }
212     }
213 
214 
215     /**
216      *  Write out content to the supplied <code>OutputStream</code>.
217      *
218      *  @param  os  XML <code>OutputStream</code>.
219      *
220      *  @throws  IOException  If any I/O error occurs.
221      */
write(OutputStream os)222     public void write(OutputStream os) throws IOException {
223 
224         // set bytes for writing to output stream
225         byte contentBytes[] = docToBytes(contentDoc);
226 
227         os.write(contentBytes);
228     }
229 
230 
231     /**
232      *  <p>Write out a <code>org.w3c.dom.Document</code> object into a
233      *  <code>byte</code> array.</p>
234      *
235      *  <p>TODO: remove dependency on com.sun.xml.tree.XmlDocument
236      *  package!</p>
237      *
238      *  @param  doc  DOM <code>Document</code> object.
239      *
240      *  @return  <code>byte</code> array of DOM <code>Document</code>
241      *           object.
242      *
243      *  @throws  IOException  If any I/O error occurs.
244      */
docToBytes(Document doc)245     private byte[] docToBytes(Document doc)
246         throws IOException {
247 
248         ByteArrayOutputStream baos = new ByteArrayOutputStream();
249 
250         java.lang.reflect.Constructor con;
251         java.lang.reflect.Method meth;
252 
253         String domImpl = doc.getClass().getName();
254 
255         System.err.println("type b " + domImpl);
256 
257         /*
258          * We may have multiple XML parsers in the Classpath.
259          * Depending on which one is first, the actual type of
260          * doc may vary.  Need a way to find out which API is being
261          * used and use an appropriate serialization method.
262          */
263         try {
264             // First of all try for JAXP 1.0
265             if (domImpl.equals("com.sun.xml.tree.XmlDocument")) {
266                 System.out.println("Using JAXP");
267                 Class jaxpDoc = Class.forName("com.sun.xml.tree.XmlDocument");
268 
269                 // The method is in the XMLDocument class itself, not a helper
270                 meth = jaxpDoc.getMethod("write",
271                             new Class[] { Class.forName("java.io.OutputStream") } );
272 
273                 meth.invoke(doc, new Object [] { baos } );
274             }
275 	    else if (domImpl.equals("org.apache.crimson.tree.XmlDocument"))
276 	    {
277 		 System.out.println("Using Crimson");
278 		 Class crimsonDoc = Class.forName("org.apache.crimson.tree.XmlDocument");
279 		 // The method is in the XMLDocument class itself, not a helper
280                 meth = crimsonDoc.getMethod("write",
281                             new Class[] { Class.forName("java.io.OutputStream") } );
282 
283                 meth.invoke(doc, new Object [] { baos } );
284 	    }
285             else if (domImpl.equals("org.apache.xerces.dom.DocumentImpl")
286             || domImpl.equals("org.apache.xerces.dom.DeferredDocumentImpl")) {
287                 System.out.println("Using Xerces");
288                 // Try for Xerces
289                 Class xercesSer =
290                         Class.forName("org.apache.xml.serialize.XMLSerializer");
291 
292                 // Get the OutputStream constructor
293                 // May want to use the OutputFormat parameter at some stage too
294                 con = xercesSer.getConstructor(new Class []
295                         { Class.forName("java.io.OutputStream"),
296                           Class.forName("org.apache.xml.serialize.OutputFormat") } );
297 
298 
299                 // Get the serialize method
300                 meth = xercesSer.getMethod("serialize",
301                             new Class [] { Class.forName("org.w3c.dom.Document") } );
302 
303 
304                 // Get an instance
305                 Object serializer = con.newInstance(new Object [] { baos, null } );
306 
307 
308                 // Now call serialize to write the document
309                 meth.invoke(serializer, new Object [] { doc } );
310             }
311             else if (domImpl.equals("gnu.xml.dom.DomDocument")) {
312                 System.out.println("Using GNU");
313 
314                 Class gnuSer = Class.forName("gnu.xml.dom.ls.DomLSSerializer");
315 
316                 // Get the serialize method
317                 meth = gnuSer.getMethod("serialize",
318                             new Class [] { Class.forName("org.w3c.dom.Node"),
319                             Class.forName("java.io.OutputStream") } );
320 
321                 // Get an instance
322                 Object serializer = gnuSer.newInstance();
323 
324                 // Now call serialize to write the document
325                 meth.invoke(serializer, new Object [] { doc, baos } );
326             }
327             else {
328                 // We dont have another parser
329                 try {
330                         DOMSource domSource = new DOMSource(doc);
331                         StringWriter writer = new StringWriter();
332                         StreamResult result = new StreamResult(writer);
333                         TransformerFactory tf = TransformerFactory.newInstance();
334                         Transformer transformer = tf.newTransformer();
335                         transformer.transform(domSource, result);
336                         return writer.toString().getBytes();
337                     }
338                 catch (Exception e) {
339                     // We don't have another parser
340                     throw new IOException("No appropriate API (JAXP/Xerces) to serialize XML document: " + domImpl);
341                 }
342             }
343         }
344         catch (ClassNotFoundException cnfe) {
345             throw new IOException(cnfe.toString());
346         }
347         catch (Exception e) {
348             // We may get some other errors, but the bottom line is that
349             // the steps being executed no longer work
350             throw new IOException(e.toString());
351         }
352 
353         byte bytes[] = baos.toByteArray();
354 
355         return bytes;
356     }
357 
358 
359     /**
360      *  Initializes a new DOM <code>Document</code> with the content
361      *  containing minimum XML tags.
362      *
363      *  @throws  IOException  If any I/O error occurs.
364      */
initContentDOM()365     public final void initContentDOM() throws IOException {
366         contentDoc = createDOM("");
367 
368     }
369 
370     /**
371      *  <p>Creates a new DOM <code>Document</code> containing minimum
372      *  OpenOffice.org XML tags.</p>
373      *
374      *  <p>This method uses the subclass
375      *  <code>getOfficeClassAttribute</code> method to get the
376      *  attribute for <i>office:class</i>.</p>
377      *
378      *  @param  rootName  root name of <code>Document</code>.
379      *
380      *  @throws  IOException  If any I/O error occurs.
381      */
createDOM(String rootName)382     private final Document createDOM(String rootName) throws IOException {
383 
384         Document doc = null;
385 
386         try {
387 
388             DocumentBuilder builder = factory.newDocumentBuilder();
389             doc = builder.newDocument();
390 
391         } catch (ParserConfigurationException ex) {
392              System.out.println("Error:"+ ex);
393 
394 
395         }
396 
397         Element root = (Element) doc.createElement(rootName);
398         doc.appendChild(root);
399 
400 
401         return doc;
402     }
403 
404 }
405 
406 
407 
408 
409