/********************************************************************** * Copyright (c) 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html  * * Contributors: * IBM Corporation - Initial API and implementation **********************************************************************/ package net.sourceforge.phpeclipse.wiki.internal; import java.io.*; import java.util.*; import java.net.URL; import org.w3c.dom.*; import org.xml.sax.*; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; /** * A Memento is a class independent container for persistence * info. It is a reflection of 3 storage requirements. * * 1) We need the ability to persist an object and restore it. * 2) The class for an object may be absent. If so we would * like to skip the object and keep reading. * 3) The class for an object may change. If so the new class * should be able to read the old persistence info. * * We could ask the objects to serialize themselves into an * ObjectOutputStream, DataOutputStream, or Hashtable. However * all of these approaches fail to meet the second requirement. * * Memento supports binary persistance with a version ID. */ public final class XMLMemento implements IMemento { private Document factory; private Element element; /** * Answer a memento for the document and element. For simplicity * you should use createReadRoot and createWriteRoot to create the initial * mementos on a document. */ public XMLMemento(Document doc, Element el) { factory = doc; element = el; } /** * @see IMemento. */ public IMemento createChild(String type) { Element child = factory.createElement(type); element.appendChild(child); return new XMLMemento(factory, child); } /** * @see IMemento. */ public IMemento createChild(String type, String id) { Element child = factory.createElement(type); child.setAttribute(TAG_ID, id); element.appendChild(child); return new XMLMemento(factory, child); } /** * Create a Document from a Reader and answer a root memento for reading * a document. */ protected static XMLMemento createReadRoot(Reader reader) { Document document = null; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder parser = factory.newDocumentBuilder(); document = parser.parse(new InputSource(reader)); Node node = document.getFirstChild(); if (node instanceof Element) return new XMLMemento(document, (Element) node); } catch (ParserConfigurationException e) { } catch (IOException e) { } catch (SAXException e) { } finally { try { reader.close(); } catch (Exception e) { } } return null; } /** * Answer a root memento for writing a document. */ public static XMLMemento createWriteRoot(String type) { Document document; try { document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); Element element = document.createElement(type); document.appendChild(element); return new XMLMemento(document, element); } catch (ParserConfigurationException e) { throw new Error(e); } } /** * @see IMemento. */ public IMemento getChild(String type) { // Get the nodes. NodeList nodes = element.getChildNodes(); int size = nodes.getLength(); if (size == 0) return null; // Find the first node which is a child of this node. for (int nX = 0; nX < size; nX ++) { Node node = nodes.item(nX); if (node instanceof Element) { Element element2 = (Element)node; if (element2.getNodeName().equals(type)) return new XMLMemento(factory, element2); } } // A child was not found. return null; } /** * @see IMemento. */ public IMemento [] getChildren(String type) { // Get the nodes. NodeList nodes = element.getChildNodes(); int size = nodes.getLength(); if (size == 0) return new IMemento[0]; // Extract each node with given fType. ArrayList list = new ArrayList(size); for (int nX = 0; nX < size; nX ++) { Node node = nodes.item(nX); if (node instanceof Element) { Element element2 = (Element)node; if (element2.getNodeName().equals(type)) list.add(element2); } } // Create a memento for each node. size = list.size(); IMemento [] results = new IMemento[size]; for (int x = 0; x < size; x ++) { results[x] = new XMLMemento(factory, (Element)list.get(x)); } return results; } /** * Return the contents of this memento as a byte array. * * @return byte[] */ public byte[] getContents() throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); save(out); return out.toByteArray(); } /** * Returns an input stream for writing to the disk with a local locale. * * @return java.io.InputStream */ public InputStream getInputStream() throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); save(out); return new ByteArrayInputStream(out.toByteArray()); } /** * @see IMemento. */ public Float getFloat(String key) { Attr attr = element.getAttributeNode(key); if (attr == null) return null; String strValue = attr.getValue(); try { return new Float(strValue); } catch (NumberFormatException e) { return null; } } /** * @see IMemento. */ public String getId() { return element.getAttribute(TAG_ID); } /** * @see IMemento. */ public String getName() { return element.getNodeName(); } /** * @see IMemento. */ public Integer getInteger(String key) { Attr attr = element.getAttributeNode(key); if (attr == null) return null; String strValue = attr.getValue(); try { return new Integer(strValue); } catch (NumberFormatException e) { return null; } } /** * @see IMemento. */ public String getString(String key) { Attr attr = element.getAttributeNode(key); if (attr == null) return null; return attr.getValue(); } public List getNames() { NamedNodeMap map = element.getAttributes(); int size = map.getLength(); List list = new ArrayList(); for (int i = 0; i < size; i++) { Node node = map.item(i); String name = node.getNodeName(); list.add(name); } return list; } /** * Loads a memento from the given filename. * * @param in java.io.InputStream * @return org.eclipse.ui.IMemento * @exception java.io.IOException */ public static IMemento loadMemento(InputStream in) { return createReadRoot(new InputStreamReader(in)); } /** * Loads a memento from the given filename. * * @param in java.io.InputStream * @return org.eclipse.ui.IMemento * @exception java.io.IOException */ public static IMemento loadCorruptMemento(InputStream in) { Document document = null; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder parser = factory.newDocumentBuilder(); document = parser.parse(in); Node node = document.getFirstChild(); if (node instanceof Element) return new XMLMemento(document, (Element) node); } catch (ParserConfigurationException e) { } catch (IOException e) { } catch (SAXException e) { } finally { try { in.close(); } catch (Exception e) { } } return null; } /** * Loads a memento from the given filename. * * @param filename java.lang.String * @return org.eclipse.ui.IMemento * @exception java.io.IOException */ public static IMemento loadMemento(String filename) throws IOException { return XMLMemento.createReadRoot(new FileReader(filename)); } /** * Loads a memento from the given filename. * * @param url java.net.URL * @return org.eclipse.ui.IMemento * @exception java.io.IOException */ public static IMemento loadMemento(URL url) throws IOException { return XMLMemento.createReadRoot(new InputStreamReader(url.openStream())); } /** * @see IMemento. */ private void putElement(Element element2) { NamedNodeMap nodeMap = element2.getAttributes(); int size = nodeMap.getLength(); for (int i = 0; i < size; i++){ Attr attr = (Attr)nodeMap.item(i); putString(attr.getName(),attr.getValue()); } NodeList nodes = element2.getChildNodes(); size = nodes.getLength(); for (int i = 0; i < size; i ++) { Node node = nodes.item(i); if (node instanceof Element) { XMLMemento child = (XMLMemento)createChild(node.getNodeName()); child.putElement((Element)node); } } } /** * @see IMemento. */ public void putFloat(String key, float f) { element.setAttribute(key, String.valueOf(f)); } /** * @see IMemento. */ public void putInteger(String key, int n) { element.setAttribute(key, String.valueOf(n)); } /** * @see IMemento. */ public void putMemento(IMemento memento) { XMLMemento xmlMemento = (XMLMemento) memento; putElement(xmlMemento.element); } /** * @see IMemento. */ public void putString(String key, String value) { if (value == null) return; element.setAttribute(key, value); } /** * Save this Memento to a Writer. */ public void save(Writer writer) throws IOException { Result result = new StreamResult(writer); Source source = new DOMSource(factory); try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ transformer.transform(source, result); } catch (Exception e) { throw (IOException) (new IOException().initCause(e)); } } /** * Save this Memento to a Writer. */ public void save(OutputStream os) throws IOException { Result result = new StreamResult(os); Source source = new DOMSource(factory); try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ transformer.transform(source, result); } catch (Exception e) { throw (IOException) (new IOException().initCause(e)); } } /** * Saves the memento to the given file. * * @param filename java.lang.String * @exception java.io.IOException */ public void saveToFile(String filename) throws IOException { Writer w = null; try { w = new FileWriter(filename); save(w); } catch (IOException e) { throw e; } catch (Exception e) { throw new IOException(e.getLocalizedMessage()); } finally { if (w != null) { try { w.close(); } catch (Exception e) { } } } } public String saveToString() throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); save(out); return out.toString("UTF-8"); } /* * @see IMemento#getBoolean(String) */ public Boolean getBoolean(String key) { Attr attr = element.getAttributeNode(key); if (attr == null) return null; String strValue = attr.getValue(); if ("true".equalsIgnoreCase(strValue)) return new Boolean(true); else return new Boolean(false); } /* * @see IMemento#putBoolean(String, boolean) */ public void putBoolean(String key, boolean value) { element.setAttribute(key, value ? "true" : "false"); } }