Source code: org/merlotxml/merlot/XMLFile.java
1 /*
2 ====================================================================
3 Copyright (c) 1999-2000 ChannelPoint, Inc.. All rights reserved.
4 ====================================================================
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 1. Redistribution of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12
13 2. Redistribution in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16
17 3. All advertising materials mentioning features or use of this
18 software must display the following acknowledgment: "This product
19 includes software developed by ChannelPoint, Inc. for use in the
20 Merlot XML Editor (http://www.merlotxml.org/)."
21
22 4. Any names trademarked by ChannelPoint, Inc. must not be used to
23 endorse or promote products derived from this software without prior
24 written permission. For written permission, please contact
25 legal@channelpoint.com.
26
27 5. Products derived from this software may not be called "Merlot"
28 nor may "Merlot" appear in their names without prior written
29 permission of ChannelPoint, Inc.
30
31 6. Redistribution of any form whatsoever must retain the following
32 acknowledgment: "This product includes software developed by
33 ChannelPoint, Inc. for use in the Merlot XML Editor
34 (http://www.merlotxml.org/)."
35
36 THIS SOFTWARE IS PROVIDED BY CHANNELPOINT, INC. "AS IS" AND ANY EXPRESSED OR
37 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
38 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
39 EVENT SHALL CHANNELPOINT, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
40 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
45 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 ====================================================================
47
48 For more information on ChannelPoint, Inc. please see http://www.channelpoint.com.
49 For information on the Merlot project, please see
50 http://www.merlotxml.org.
51 */
52
53
54 // Copyright 1999 ChannelPoint, Inc., All Rights Reserved.
55
56 package org.merlotxml.merlot;
57
58 import java.awt.*;
59
60 import java.beans.*;
61 import java.io.*;
62 import javax.swing.*;
63 import java.util.*;
64
65 import org.w3c.dom.*;
66
67 import org.merlotxml.util.xml.*;
68 import org.merlotxml.util.*;
69 import org.merlotxml.util.xml.xerces.DOMLiaison;
70
71
72 /**
73 *
74 * An XML file. This provides an internface into a particular XML file,
75 * including its dtd and its file location. It provides methods for
76 * loading and parsing a file, saving a file, and accessing the content
77 * model in the dtd.
78 *
79 *
80 * @author Kelly A. Campbell
81 *
82 * @version $Id: XMLFile.java,v 1.3 2002/01/16 17:46:25 flament Exp $
83 *
84 */
85 public class XMLFile
86 implements MerlotConstants
87
88 {
89 /**
90 * The parsed DOM document with validation
91 */
92 protected ValidDocument _doc = null;
93
94 /**
95 * The document type (dtd)
96 */
97 protected DocumentType _docType = null;
98
99 /**
100 * The file on the filesystem
101 */
102 protected File _file = null;
103
104 /**
105 * Status holder for marking the file as needing a save
106 */
107 protected boolean _dirty = false;
108 /**
109 * Status marker for brand new files so we can call saveas instead of save
110 */
111 protected boolean _new = false;
112
113 /**
114 * property change delegate
115 */
116 protected PropertyChangeSupport _propchange;
117
118 /**
119 * Reads in the given filename to create the Document tree
120 */
121
122 public XMLFile (File f)
123 throws MerlotException
124 {
125
126 _file = f;
127
128 _propchange = new PropertyChangeSupport(this);
129
130 // now parse the file and get a Document
131 parseDocument();
132
133 }
134
135 /**
136 * creates a new file with a blank Document tree
137 */
138 public XMLFile ()
139 throws MerlotException
140 {
141
142 _propchange = new PropertyChangeSupport(this);
143
144 _doc = XMLEditor.getSharedInstance().getDOMLiaison().createValidDocument();
145 }
146
147 /**
148 * Returns the DOM document for this file
149 */
150 public Document getDocument()
151 {
152 return _doc.getDocument();
153 }
154
155 /**
156 * Returns the DOMLiaison ValidDocument wrapper for this file
157 */
158 public ValidDocument getValidDocument()
159 {
160 return _doc;
161 }
162
163 /**
164 * Returns the main DTDDocument for this file
165 */
166 public DTDDocument getDTD(String name)
167 {
168 return _doc.getDTDDocument(name);
169 }
170
171 /**
172 * returns the DTDCacheEntry for this document. Useful to get access to the
173 * DTD plugin associated with this file
174 */
175 public DTDCacheEntry getDTDCacheEntry()
176 {
177 return _doc.getDTDCacheEntry();
178 }
179
180 /**
181 * Sets the new property
182 */
183 public void setNew(boolean tf)
184 {
185 _new = tf;
186 }
187
188 /**
189 * returns the new property
190 */
191 public boolean isNew()
192 {
193 return _new;
194 }
195
196 /*
197 /* *
198 * sets this to the given document replacing the previous one
199 * /
200 public void setDocument(Document doc)
201 {
202 //XXX _doc = doc;
203 // update this to handle setDocument for the new valid parser liaison
204 }
205 */
206
207 public DocumentType getDoctype()
208 {
209 return _docType;
210 }
211
212
213 protected void parseDocument()
214 throws MerlotException
215 {
216
217 try {
218 InputStream fis = FileUtil.getInputStream(_file, this.getClass());
219 // get a DOMLiaison from the settings and parse the given file
220 ValidDOMLiaison domlia = XMLEditor.getSharedInstance().getDOMLiaison();
221 if (domlia != null) {
222 _doc = domlia.parseValidXMLStream(fis,_file.getCanonicalPath());
223 }
224 if (_doc != null || _doc.getDocument() == null) {
225 _docType = _doc.getDocument().getDoctype();
226 }
227 else {
228 throw new MerlotException(MerlotResource.getString(ERR, "xml.file.open.nodocument"));
229 }
230
231 }
232 catch (FileNotFoundException fnf) {
233 MerlotDebug.exception(fnf);
234 throw new MerlotException("File not found: "+ _file, fnf);
235 }
236 catch (IOException ioex) {
237 MerlotDebug.exception(ioex);
238 throw new MerlotException("IOException: "+ _file, ioex);
239 }
240
241 catch (DOMLiaisonImplException dle) {
242 Exception blah = dle.getRealException();
243 if (blah != null) {
244 MerlotDebug.msg("dle.msessage = "+dle.getMessage());
245
246 MerlotDebug.exception(dle);
247 }
248 else {
249 MerlotDebug.msg("wrapper exception with a null real exception");
250 }
251
252 throw new MerlotException("Parse error: "+dle.getMessage(), dle);
253 }
254
255
256
257 }
258
259
260 public void printRawXML (OutputStream s, boolean pretty)
261 throws MerlotException
262 {
263 try {
264 Writer w;
265 String encoding = _doc.getEncoding();
266 if (encoding != null) {
267 w = new OutputStreamWriter(s,encoding);
268 }
269 else {
270 w = new OutputStreamWriter(s);
271 }
272
273 XMLEditor.getSharedInstance().getDOMLiaison().print(_doc,w,null,pretty);
274 /* Xerces pretty printing is really bad in some cases. going back to original save routine
275
276 DOMLiaison xercesDomLiaison = new DOMLiaison();
277 xercesDomLiaison.print(_doc,w,null,pretty);
278 */
279 }
280 catch (Exception ex) {
281 MerlotDebug.exception(ex);
282 throw new MerlotException (MerlotResource.getString(ERR,"xml.file.write.err"),ex);
283 }
284
285 }
286
287
288 public String getName()
289 {
290 return _file.getName();
291 }
292
293 public String getPath()
294 {
295 return _file.getPath();
296 }
297
298 public Enumeration getDTDAttributes(String elementName)
299 {
300 return _doc.getDTDAttributes(elementName);
301 }
302
303 /*
304 public Enumeration getAppendableElements(Element el) {
305 DTDDocument doc = _doc.getDTDForElement(el);
306 if (doc != null) {
307 Enumeration e = doc.getAppendableElements(el);
308 return e;
309 }
310 return null;
311 }
312 */
313 public Enumeration getInsertableElements(Element el, int index)
314 {
315 DTDDocument doc = _doc.getDTDForElement(el);
316 if (doc != null) {
317 Enumeration e = doc.getInsertableElements(el, index);
318 return e;
319 }
320 return null;
321 }
322
323 public boolean elementIsValid (Element el, boolean checkChildren)
324 {
325 DTDDocument doc = _doc.getDTDForElement(el);
326 if (doc == null)
327 return false;
328 return doc.elementIsValid(el,checkChildren);
329 }
330
331 public void setDirty(boolean tf)
332 {
333 boolean old = _dirty;
334 _dirty = tf;
335
336 firePropertyChange("dirty",old,tf);
337
338
339 }
340
341 public boolean isDirty()
342 {
343 return _dirty;
344 }
345
346 public void addPropertyChangeListener(PropertyChangeListener l)
347 {
348 _propchange.addPropertyChangeListener(l);
349 }
350
351 public void firePropertyChange(String s, boolean ov, boolean nv)
352 {
353 MerlotDebug.msg("XMLFile firePropertyChange: "+s);
354
355 _propchange.firePropertyChange(s,ov,nv);
356 }
357
358 /**
359 * Saves in the same file we opened
360 */
361 public void save()
362 throws MerlotException
363 {
364 saveAs(_file);
365
366 }
367
368 /**
369 * Saves to a new file
370 */
371 public void saveAs(File f)
372 throws MerlotException
373 {
374 try {
375
376 // keep a backup of the original file incase the saveAs fails
377 File tmpFile = new File(f.getAbsolutePath() + ".tmpsave");
378
379 // _file = f;
380 OutputStream s = new FileOutputStream(tmpFile);
381 printRawXML(s,/*=$* true *=$*/false);
382 s.close();
383
384
385 // if it didn't work an exception will be thrown and we won't get here
386 // now replace the old file with the tmp one
387 File backup = new File(_file.getAbsolutePath() + ".$$$");
388 // if the backup already exists... remove it
389 boolean tf;
390 if (backup.exists()) {
391 tf = backup.delete();
392 MerlotDebug.msg("Deleting "+backup+" returns "+tf);
393 }
394 if (!_new) MerlotUtils.copyFile(_file, backup);
395 MerlotUtils.copyFile(tmpFile,f);
396 tf = tmpFile.delete();
397 MerlotDebug.msg("Deleting "+tmpFile+" returns "+tf);
398
399
400 _file = f;
401
402 setDirty(false);
403 setNew(false);
404
405 }
406 catch (IOException ex){
407 throw new MerlotException("IOException while saving file: "+ex.getMessage(), ex);
408 }
409
410 }
411
412 }