Small fix to tidy up the run menu. Axel will likely roll this back once he gets more...
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.wiki / src / net / sourceforge / phpeclipse / wiki / internal / XMLMemento.java
1 /**********************************************************************
2  * Copyright (c) 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - Initial API and implementation
10  **********************************************************************/
11 package net.sourceforge.phpeclipse.wiki.internal;
12
13 import java.io.*;
14 import java.util.*;
15 import java.net.URL;
16 import org.w3c.dom.*;
17 import org.xml.sax.*;
18
19 import javax.xml.parsers.*;
20 import javax.xml.transform.*;
21 import javax.xml.transform.dom.DOMSource;
22 import javax.xml.transform.stream.StreamResult;
23 /**
24  * A Memento is a class independent container for persistence
25  * info.  It is a reflection of 3 storage requirements.
26  *
27  * 1)   We need the ability to persist an object and restore it.  
28  * 2)   The class for an object may be absent.  If so we would 
29  *      like to skip the object and keep reading. 
30  * 3)   The class for an object may change.  If so the new class 
31  *      should be able to read the old persistence info.
32  *
33  * We could ask the objects to serialize themselves into an 
34  * ObjectOutputStream, DataOutputStream, or Hashtable.  However 
35  * all of these approaches fail to meet the second requirement.
36  *
37  * Memento supports binary persistance with a version ID.
38  */
39 public final class XMLMemento implements IMemento {
40         private Document factory;
41         private Element element;
42
43         /**
44          * Answer a memento for the document and element.  For simplicity
45          * you should use createReadRoot and createWriteRoot to create the initial
46          * mementos on a document.
47          */
48         public XMLMemento(Document doc, Element el) {
49                 factory = doc;
50                 element = el;
51         }
52
53         /**
54          * @see IMemento.
55          */
56         public IMemento createChild(String type) {
57                 Element child = factory.createElement(type);
58                 element.appendChild(child);
59                 return new XMLMemento(factory, child);
60         }
61
62         /**
63          * @see IMemento.
64          */
65         public IMemento createChild(String type, String id) {
66                 Element child = factory.createElement(type);
67                 child.setAttribute(TAG_ID, id);
68                 element.appendChild(child);
69                 return new XMLMemento(factory, child);
70         }
71
72         /**
73          * Create a Document from a Reader and answer a root memento for reading 
74          * a document.
75          */
76         protected static XMLMemento createReadRoot(Reader reader) {
77                 Document document = null;
78                 try {
79                         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
80                         DocumentBuilder parser = factory.newDocumentBuilder();
81                         document = parser.parse(new InputSource(reader));
82                         Node node = document.getFirstChild();
83                         if (node instanceof Element)
84                                 return new XMLMemento(document, (Element) node);
85                 } catch (ParserConfigurationException e) {
86                 } catch (IOException e) {
87                 } catch (SAXException e) {
88                 } finally {
89                         try {
90                                 reader.close();
91                         } catch (Exception e) { }
92                 }
93                 return null;
94         }
95         
96         /**
97          * Answer a root memento for writing a document.
98          */
99         public static XMLMemento createWriteRoot(String type) {
100                 Document document;
101                 try {
102                         document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
103                         Element element = document.createElement(type);
104                         document.appendChild(element);
105                         return new XMLMemento(document, element);            
106                 } catch (ParserConfigurationException e) {
107                         throw new Error(e);
108                 }
109         }
110         
111         /**
112          * @see IMemento.
113          */
114         public IMemento getChild(String type) {
115                 // Get the nodes.
116                 NodeList nodes = element.getChildNodes();
117                 int size = nodes.getLength();
118                 if (size == 0)
119                         return null;
120         
121                 // Find the first node which is a child of this node.
122                 for (int nX = 0; nX < size; nX ++) {
123                         Node node = nodes.item(nX);
124                         if (node instanceof Element) {
125                                 Element element2 = (Element)node;
126                                 if (element2.getNodeName().equals(type))
127                                         return new XMLMemento(factory, element2);
128                         }
129                 }
130         
131                 // A child was not found.
132                 return null;
133         }
134
135         /**
136          * @see IMemento.
137          */
138         public IMemento [] getChildren(String type) {
139                 // Get the nodes.
140                 NodeList nodes = element.getChildNodes();
141                 int size = nodes.getLength();
142                 if (size == 0)
143                         return new IMemento[0];
144         
145                 // Extract each node with given fType.
146                 ArrayList list = new ArrayList(size);
147                 for (int nX = 0; nX < size; nX ++) {
148                         Node node = nodes.item(nX);
149                         if (node instanceof Element) {
150                                 Element element2 = (Element)node;
151                                 if (element2.getNodeName().equals(type))
152                                         list.add(element2);
153                         }
154                 }
155         
156                 // Create a memento for each node.
157                 size = list.size();
158                 IMemento [] results = new IMemento[size];
159                 for (int x = 0; x < size; x ++) {
160                         results[x] = new XMLMemento(factory, (Element)list.get(x));
161                 }
162                 return results;
163         }
164
165         /**
166          * Return the contents of this memento as a byte array.
167          *
168          * @return byte[]
169          */
170         public byte[] getContents() throws IOException {
171                 ByteArrayOutputStream out = new ByteArrayOutputStream();
172                 save(out);
173                 return out.toByteArray();
174         }
175
176         /**
177          * Returns an input stream for writing to the disk with a local locale.
178          *
179          * @return java.io.InputStream
180          */
181         public InputStream getInputStream() throws IOException {
182                 ByteArrayOutputStream out = new ByteArrayOutputStream();
183                 save(out);
184                 return new ByteArrayInputStream(out.toByteArray());
185         }
186
187         /**
188          * @see IMemento.
189          */
190         public Float getFloat(String key) {
191                 Attr attr = element.getAttributeNode(key);
192                 if (attr == null)
193                         return null; 
194                 String strValue = attr.getValue();
195                 try {
196                         return new Float(strValue);
197                 } catch (NumberFormatException e) {
198                         return null;
199                 }
200         }
201
202         /**
203          * @see IMemento.
204          */
205         public String getId() {
206                 return element.getAttribute(TAG_ID);
207         }
208         
209         /**
210          * @see IMemento.
211          */
212         public String getName() {
213                 return element.getNodeName();
214         }
215
216         /**
217          * @see IMemento.
218          */
219         public Integer getInteger(String key) {
220                 Attr attr = element.getAttributeNode(key);
221                 if (attr == null)
222                         return null; 
223                 String strValue = attr.getValue();
224                 try {
225                         return new Integer(strValue);
226                 } catch (NumberFormatException e) {
227                         return null;
228                 }
229         }
230
231         /**
232          * @see IMemento.
233          */
234         public String getString(String key) {
235                 Attr attr = element.getAttributeNode(key);
236                 if (attr == null)
237                         return null; 
238                 return attr.getValue();
239         }
240         
241         public List getNames() {
242                 NamedNodeMap map = element.getAttributes();
243                 int size = map.getLength();
244                 List list = new ArrayList();
245                 for (int i = 0; i < size; i++) {
246                         Node node = map.item(i);
247                         String name = node.getNodeName();
248                         list.add(name);
249                 }
250                 return list;
251         }
252
253         /**
254          * Loads a memento from the given filename.
255          *
256          * @param in java.io.InputStream
257          * @return org.eclipse.ui.IMemento
258          * @exception java.io.IOException
259          */
260         public static IMemento loadMemento(InputStream in) {
261                 return createReadRoot(new InputStreamReader(in));
262         }
263         
264         /**
265          * Loads a memento from the given filename.
266          *
267          * @param in java.io.InputStream
268          * @return org.eclipse.ui.IMemento
269          * @exception java.io.IOException
270          */
271         public static IMemento loadCorruptMemento(InputStream in) {
272                 Document document = null;
273                 try {
274                         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
275                         DocumentBuilder parser = factory.newDocumentBuilder();
276                         document = parser.parse(in);
277                         Node node = document.getFirstChild();
278                         if (node instanceof Element)
279                                 return new XMLMemento(document, (Element) node);
280                 } catch (ParserConfigurationException e) {
281                 } catch (IOException e) {
282                 } catch (SAXException e) {
283                 } finally {
284                         try {
285                                 in.close();
286                         } catch (Exception e) { }
287                 }
288                 return null;
289         }
290
291         /**
292          * Loads a memento from the given filename.
293          *
294          * @param filename java.lang.String
295          * @return org.eclipse.ui.IMemento
296          * @exception java.io.IOException
297          */
298         public static IMemento loadMemento(String filename) throws IOException {
299                 return XMLMemento.createReadRoot(new FileReader(filename));
300         }
301
302         /**
303          * Loads a memento from the given filename.
304          *
305          * @param url java.net.URL
306          * @return org.eclipse.ui.IMemento
307          * @exception java.io.IOException
308          */
309         public static IMemento loadMemento(URL url) throws IOException {
310                 return XMLMemento.createReadRoot(new InputStreamReader(url.openStream()));
311         }
312
313         /**
314          * @see IMemento.
315          */
316         private void putElement(Element element2) {
317                 NamedNodeMap nodeMap = element2.getAttributes();
318                 int size = nodeMap.getLength();
319                 for (int i = 0; i < size; i++){
320                         Attr attr = (Attr)nodeMap.item(i);
321                         putString(attr.getName(),attr.getValue());
322                 }
323                 
324                 NodeList nodes = element2.getChildNodes();
325                 size = nodes.getLength();
326                 for (int i = 0; i < size; i ++) {
327                         Node node = nodes.item(i);
328                         if (node instanceof Element) {
329                                 XMLMemento child = (XMLMemento)createChild(node.getNodeName());
330                                 child.putElement((Element)node);
331                         }
332                 }
333         }
334
335         /**
336          * @see IMemento.
337          */
338         public void putFloat(String key, float f) {
339                 element.setAttribute(key, String.valueOf(f));
340         }
341
342         /**
343          * @see IMemento.
344          */
345         public void putInteger(String key, int n) {
346                 element.setAttribute(key, String.valueOf(n));
347         }
348
349         /**
350          * @see IMemento.
351          */
352         public void putMemento(IMemento memento) {
353                 XMLMemento xmlMemento = (XMLMemento) memento;
354                 putElement(xmlMemento.element);
355         }
356
357         /**
358          * @see IMemento.
359          */
360         public void putString(String key, String value) {
361                 if (value == null)
362                         return;
363                 element.setAttribute(key, value);
364         }
365
366         /**
367          * Save this Memento to a Writer.
368          */
369         public void save(Writer writer) throws IOException {
370                 Result result = new StreamResult(writer);
371                 Source source = new DOMSource(factory);
372                 try {
373                         Transformer transformer = TransformerFactory.newInstance().newTransformer();
374                         transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
375                         transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
376                         transformer.transform(source, result);            
377                 } catch (Exception e) {
378                         throw (IOException) (new IOException().initCause(e));
379                 }
380         }
381         
382         /**
383          * Save this Memento to a Writer.
384          */
385         public void save(OutputStream os) throws IOException {
386                 Result result = new StreamResult(os);
387                 Source source = new DOMSource(factory);
388                 try {
389                         Transformer transformer = TransformerFactory.newInstance().newTransformer();
390                         transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
391                         transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
392                         transformer.transform(source, result);            
393                 } catch (Exception e) {
394                         throw (IOException) (new IOException().initCause(e));
395                 }
396         }
397
398         /**
399          * Saves the memento to the given file.
400          *
401          * @param filename java.lang.String
402          * @exception java.io.IOException
403          */
404         public void saveToFile(String filename) throws IOException {
405                 Writer w = null;
406                 try {
407                         w = new FileWriter(filename);
408                         save(w);
409                 } catch (IOException e) {
410                         throw e;
411                 } catch (Exception e) {
412                         throw new IOException(e.getLocalizedMessage());
413                 } finally {
414                         if (w != null) {
415                                 try {
416                                         w.close();
417                                 } catch (Exception e) { }
418                         }
419                 }
420         }
421         
422         public String saveToString() throws IOException {
423                 ByteArrayOutputStream out = new ByteArrayOutputStream();
424                 save(out);
425                 return out.toString("UTF-8");
426         }
427         
428         /*
429          * @see IMemento#getBoolean(String)
430          */
431         public Boolean getBoolean(String key) {
432                 Attr attr = element.getAttributeNode(key);
433                 if (attr == null)
434                         return null;
435                 String strValue = attr.getValue();
436                 if ("true".equalsIgnoreCase(strValue))
437                         return new Boolean(true);
438                 else
439                         return new Boolean(false);
440         }
441
442         /*
443          * @see IMemento#putBoolean(String, boolean)
444          */
445         public void putBoolean(String key, boolean value) {
446                 element.setAttribute(key, value ? "true" : "false");
447         }
448 }