// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
// Released under the terms of the CPL Common Public License version 1.0.
package fitnesse.wiki;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import util.Clock;
import util.XmlUtil;
import util.XmlWriter;
import fitnesse.wikitext.Utils;
public class WikiPageProperties extends WikiPageProperty implements Serializable {
private static final long serialVersionUID = 1L;
public static final String VIRTUAL_WIKI_ATTRIBUTE = "VirtualWiki";
private Map<?, ?> symbolicLinks;
public WikiPageProperties() {
symbolicLinks = new HashMap<Object, Object>();
}
public WikiPageProperties(InputStream inputStream) {
this();
loadFromXmlStream(inputStream);
}
public WikiPageProperties(Element rootElement) {
this();
loadFromRootElement(rootElement);
}
public WikiPageProperties(WikiPageProperties that) {
if (that != null && that.children != null)
children = new HashMap<String, WikiPageProperty>(that.children);
symbolicLinks = new HashMap<Object, Object>(that.symbolicLinks);
}
public void loadFromXmlStream(InputStream inputStream) {
Document document;
try {
document = XmlUtil.newDocument(inputStream);
} catch (Exception e) {
throw new RuntimeException("Unable to parse XML from stream", e);
}
Element root = document.getDocumentElement();
loadFromRootElement(root);
}
public void loadFromRootElement(Element root) {
NodeList nodes = root.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node.getNodeType() != Node.ELEMENT_NODE)
continue;
String key = node.getNodeName();
LoadElement(this, (Element) node, key);
}
}
private void LoadElement(WikiPageProperty context, Element element, String key) {
WikiPageProperty newProperty = new WikiPageProperty();
context.set(key, newProperty);
NodeList nodes = element.getChildNodes();
if (element.hasAttribute("value"))
newProperty.setValue(element.getAttribute("value"));
else if (nodes.getLength() == 1)
newProperty.setValue(nodes.item(0).getNodeValue());
for (int i = 0; i < nodes.getLength(); i++) {
Node childNode = nodes.item(i);
if (childNode instanceof Element)
LoadElement(newProperty, (Element) childNode, childNode.getNodeName());
}
}
public void save(OutputStream outputStream) throws Exception {
Document document = null;
XmlWriter writer = null;
try {
document = XmlUtil.newDocument();
document.appendChild(makeRootElement(document));
writer = new XmlWriter(outputStream);
writer.write(document);
} finally {
if (writer != null) {
writer.flush();
writer.close();
}
}
}
public Element makeRootElement(Document document) {
Element root = document.createElement("properties");
List<String> keys = new ArrayList<String>(keySet());
Collections.sort(keys);
for (Iterator<String> iterator = keys.iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
WikiPageProperty childProperty = getProperty(key);
toXml(childProperty, key, document, root);
}
return root;
}
private void toXml(WikiPageProperty context, String key, Document document, Element parent) {
Element element = document.createElement(key);
String value = context.getValue();
if (context.hasChildren()) {
if (value != null)
element.setAttribute("value", value);
Set<?> childKeys = context.keySet();
for (Iterator<?> iterator = childKeys.iterator(); iterator.hasNext();) {
String childKey = (String) iterator.next();
WikiPageProperty child = context.getProperty(childKey);
if (child == null) {
System.err.println("Property key \"" + childKey + "\" has null value for {" + context + "}");
} else {
toXml(child, childKey, document, element);
}
}
} else if (value != null)
element.appendChild(document.createTextNode(Utils.escapeHTML(value)));
parent.appendChild(element);
}
public String toString() {
StringBuffer s = new StringBuffer();
s.append(super.toString("WikiPageProperties", 0));
return s.toString();
}
public Date getLastModificationTime() {
String dateStr = get(PageData.PropertyLAST_MODIFIED);
if (dateStr == null)
return Clock.currentDate();
else
try {
return getTimeFormat().parse(dateStr);
} catch (ParseException e) {
throw new RuntimeException("Unable to parse date '" + dateStr + "'", e);
}
}
public void setLastModificationTime(Date date) {
set(PageData.PropertyLAST_MODIFIED, getTimeFormat().format(date));
}
}