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