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