|
From: Dan C. <dch...@us...> - 2006-06-08 17:01:01
|
Update of /cvsroot/xorm/xorm/src/org/xorm/datastore/xml In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv23547/src/org/xorm/datastore/xml Modified Files: Tag: dan-w3c-dom DocumentHolder.java JDOMDocumentDriver.java XMLConnectionInfo.java Added Files: JDOMDocumentHolder.java W3CDocumentDriver.java W3CDocumentHolder.java Log Message: Doing this on a branch... Added W3C DOM support in an effort (perhaps) to rid XORM of JDOM. --- NEW FILE: W3CDocumentDriver.java --- /* $Header: /cvsroot/xorm/xorm/src/org/xorm/datastore/xml/W3CDocumentDriver.java,v 1.1 2006/06/08 17:00:50 dcheckoway Exp $ This file is part of XORM. XORM is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. XORM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with XORM; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.xorm.datastore.xml; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Set; import org.xorm.datastore.Row; import org.xorm.datastore.Column; import org.xorm.datastore.Table; import org.xorm.datastore.DataFetchGroup; import org.xorm.datastore.DatastoreDriver; import org.xorm.datastore.DriverException; import org.xorm.query.Condition; import org.xorm.query.Selector; import org.xorm.query.SimpleCondition; import org.xorm.util.TypeConverter; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * A datastore driver that uses an XML document as the datastore. * Datastore XML descriptor files need to specify a column named "." * as the primary key column; table names should match element names. * Data column names should be specified in a limited XPath notation. * Examples are "@name", "description/text()", and ".." for a parent * reference. * * This class relies on the transactional mechanics of the DocumentHolder * class. At the beginning of each transaction, it acquires a document * by calling checkout(); upon commit (but not rollback) it calls * checkin(). * * @author Dan Checkoway */ public class W3CDocumentDriver implements DatastoreDriver { private DocumentHolder documentHolder; private Document document; private boolean readOnly; private boolean onlyDidReads; /** * Sets the data source, which must be an instance of DocumentHolder. */ public W3CDocumentDriver(URL url) { documentHolder = new W3CDocumentHolder(); documentHolder.setURL(url); } /** * Begins a transaction by calling checkout on the DocumentHolder. */ public void begin(boolean readOnly) { document = (Document)documentHolder.checkout(); this.readOnly = readOnly; onlyDidReads = true; } /** * Calls checkin() on the DocumentHolder if any write operations * were called during the transaction. */ public void commit() throws DriverException { if (!onlyDidReads) { documentHolder.checkin(document); } document = null; // reacquire in next transaction } public void rollback() { document = null; // reacquire in next transaction } // CRUD methods public void create(Row row) { onlyDidReads = false; Table table = row.getTable(); Column primaryKey = table.getPrimaryKey(); Element element = document.createElement(table.getName()); row.setValue(primaryKey, element); Iterator it = table.getColumns().iterator(); while (it.hasNext()) { Column c = (Column) it.next(); setValue(element, c, row.getValue(c), true); } // If the newly created element is unattached at this point, // it is not contained within any other element tag, and therefore // it must be added under the document root. if (element.getParentNode() == null && !element.isSameNode(document.getDocumentElement())) { document.getDocumentElement().appendChild(element); } } public void update(Row row) { onlyDidReads = false; Table table = row.getTable(); Column primaryKey = table.getPrimaryKey(); Element element = (Element) row.getValue(primaryKey); Iterator it = table.getColumns().iterator(); while (it.hasNext()) { Column c = (Column) it.next(); if (row.isDirty(c)) { setValue(element, c, row.getValue(c), false); } } } public void delete(Row row) { onlyDidReads = false; Table table = row.getTable(); Column primaryKey = table.getPrimaryKey(); Element element = (Element) row.getValue(primaryKey); if (element.getParentNode() != null) { element.getParentNode().removeChild(element); } // TODO: deal with cascaded delete ramifications on the cache } public Collection select(Selector selector, Set extraRows) { Condition condition = selector.getCondition(); Table table = selector.getTable(); Collection xmlResults = null; if (condition == null) { xmlResults = new ArrayList(); xmlResults.add(deriveValue(document.getDocumentElement(), table.getName())); } else if (condition instanceof SimpleCondition) { SimpleCondition sc = (SimpleCondition) condition; Column column = sc.getColumn(); Object value = sc.getValue(); // ".." == (Element) means get all children of an element // with an element name matching the table name. if ("..".equals(column.getName()) && (value instanceof Element)) { Element parent = (Element) value; NodeList children = parent.getElementsByTagName(table.getName()); xmlResults = new ArrayList(); for (int c = 0; c < children.getLength(); ++c) { xmlResults.add(children.item(c)); } } } // Populate the rows ArrayList rows = new ArrayList(); if (xmlResults == null) return rows; // no results Iterator i = xmlResults.iterator(); while (i.hasNext()) { Element element = (Element)i.next(); Row row = new Row(table); populate(row, element); rows.add(row); } return rows; } private void populate(Row row, Element element) { Iterator j = row.getTable().getColumns().iterator(); while (j.hasNext()) { Column c = (Column) j.next(); Object value = deriveValue(element, c.getName()); if (value instanceof String) { // Convert to Java Type Class javaType = XMLType.forName(c.getType()); if (javaType != null) { value = TypeConverter.convertToType(value, javaType, c.getFormat()); } } row.setValue(c, value); } } public int count(Selector selector) { return select(selector, null).size(); } // Path corresponds to a very small subset of abbreviated XPath syntax private Object deriveValue(Element element, String path) { int pos = path.lastIndexOf('/'); if (pos != -1) { element = navigateToElement(element, path, false); path = path.substring(pos + 1); } // attribute if (path.startsWith("@")) { return element.getAttribute(path.substring(1)); } // text node if ("text()".equals(path)) { String text = element.getTextContent(); if (text != null) { text = text.trim(); } return text; } if (".".equals(path)) { return element; } else if ("..".equals(path)) { return element.getParentNode(); } else { return (Element)element.getElementsByTagName(path).item(0); } } /** * Returns the Element indicated by the subpath (everything up to * the last '/'). */ private Element navigateToElement(Element element, String path, boolean create) { int pos = path.indexOf('/'); String pathTail = null; if (pos != -1) { pathTail = path.substring(pos + 1); path = path.substring(0, pos); if ("..".equals(path)) { Node parent = element.getParentNode(); if (parent instanceof Element) { element = (Element)parent; } else { // DAS: What to do? return element; } } else { Element parent = element; element = (Element)element.getElementsByTagName(path).item(0); if (create && (element == null)) { element = document.createElement(path); parent.appendChild(element); } } return navigateToElement(element, pathTail, create); } return element; } private void setValue(Element element, Column c, Object value, boolean create) { String path = c.getName(); if (!(value instanceof Element)) { // Convert value to String value = TypeConverter.convertToType(value, String.class, c.getFormat()); } int pos = path.lastIndexOf('/'); if (pos != -1) { element = navigateToElement(element, path, create); path = path.substring(pos + 1); } // attribute if (path.startsWith("@")) { Attr attr = document.createAttribute(path.substring(1)); attr.setValue((String)value); element.getAttributes().setNamedItem(attr); } else if ("text()".equals(path)) { element.setTextContent((String)value); } else if (".".equals(path)) { // self-reference (primary key) -- ignore } else if ("..".equals(path)) { Element parent = (Element)value; if (element.getParentNode() != null) { element.getParentNode().removeChild(element); } parent.appendChild(element); } else { // Child reference element.appendChild((Element)value); } } } --- NEW FILE: JDOMDocumentHolder.java --- /* $Header: /cvsroot/xorm/xorm/src/org/xorm/datastore/xml/JDOMDocumentHolder.java,v 1.1 2006/06/08 17:00:50 dcheckoway Exp $ This file is part of XORM. XORM is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. XORM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with XORM; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.xorm.datastore.xml; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; import java.net.MalformedURLException; import org.jdom.Document; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.jdom.output.XMLOutputter; /** * Wraps a JDOM Document and allows transactional access. * * @author Wes Biggs */ public class JDOMDocumentHolder implements DocumentHolder { private URL url; private Document document; public JDOMDocumentHolder() {} public void setURL(URL url) { this.url = url; try { document = new SAXBuilder().build(url); } catch (JDOMException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * Returns a cloned copy of the document. */ public Object checkout() { return document.clone(); } /** * Accepts the changes from the document. If possible, rewrites * the content. Changes are synchronized but not checked; if two * concurrent threads make different changes, the last one to call * checkin() will win. This effectively gives the process a * transaction isolation level equivalent to TRANSACTION_READ_COMMITTED. */ public void checkin(Object _document) { this.document = (Document)_document; synchronized (url) { OutputStream outputStream = null; try { if ("file".equals(url.getProtocol())) { outputStream = new FileOutputStream(url.getFile()); } else { // Try to set "doOutput", may not work URLConnection connection = url.openConnection(); connection.setDoOutput(true); outputStream = connection.getOutputStream(); } new XMLOutputter(" ", true).output(this.document, outputStream); outputStream.flush(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } // synchronized } } --- NEW FILE: W3CDocumentHolder.java --- /* $Header: /cvsroot/xorm/xorm/src/org/xorm/datastore/xml/W3CDocumentHolder.java,v 1.1 2006/06/08 17:00:50 dcheckoway Exp $ This file is part of XORM. XORM is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. XORM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with XORM; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.xorm.datastore.xml; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.xml.sax.SAXException; /** * Wraps a W3C Document and allows transactional access. * * @author Dan Checkoway */ public class W3CDocumentHolder implements DocumentHolder { private DocumentBuilder docBuilder; private URL url; private Document document; public W3CDocumentHolder() {} public void setURL(URL url) { this.url = url; try { docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); document = docBuilder.parse(url.openStream()); } catch (javax.xml.parsers.ParserConfigurationException e) { e.printStackTrace(); } catch (IOException e) { throw new RuntimeException(e); } catch (SAXException e) { throw new RuntimeException(e); } } /** * Returns a cloned copy of the document. */ public Object checkout() { Document copy = docBuilder.newDocument(); try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.transform(new DOMSource(document), new DOMResult(copy)); } catch (javax.xml.transform.TransformerException e) { e.printStackTrace(); } return copy; } /** * Accepts the changes from the document. If possible, rewrites * the content. Changes are synchronized but not checked; if two * concurrent threads make different changes, the last one to call * checkin() will win. This effectively gives the process a * transaction isolation level equivalent to TRANSACTION_READ_COMMITTED. */ public void checkin(Object _document) { this.document = (Document)_document; synchronized (url) { OutputStream outputStream = null; try { if ("file".equals(url.getProtocol())) { outputStream = new FileOutputStream(url.getFile()); } else { // Try to set "doOutput", may not work URLConnection connection = url.openConnection(); connection.setDoOutput(true); outputStream = connection.getOutputStream(); } Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.transform(new DOMSource(document), new StreamResult(outputStream)); outputStream.flush(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } catch (javax.xml.transform.TransformerException e) { e.printStackTrace(); } } // synchronized } } Index: DocumentHolder.java =================================================================== RCS file: /cvsroot/xorm/xorm/src/org/xorm/datastore/xml/DocumentHolder.java,v retrieving revision 1.2 retrieving revision 1.2.4.1 diff -C2 -d -r1.2 -r1.2.4.1 *** DocumentHolder.java 15 Jul 2003 22:53:10 -0000 1.2 --- DocumentHolder.java 8 Jun 2006 17:00:50 -0000 1.2.4.1 *************** *** 20,91 **** package org.xorm.datastore.xml; - import java.io.FileOutputStream; - import java.io.IOException; - import java.io.OutputStream; - import java.net.URL; - import java.net.URLConnection; - import java.net.MalformedURLException; - - import org.jdom.Document; - import org.jdom.JDOMException; - import org.jdom.input.SAXBuilder; - import org.jdom.output.XMLOutputter; /** ! * Wraps a JDOM Document and allows transactional access. * ! * @author Wes Biggs */ ! public class DocumentHolder { ! private URL url; ! private Document document; ! ! public DocumentHolder(URL url) { ! this.url = url; ! try { ! document = new SAXBuilder().build(url); ! } catch (JDOMException e) { ! e.printStackTrace(); ! } catch (IOException e) { ! e.printStackTrace(); ! } ! } ! ! /** ! * Returns a cloned copy of the document. ! */ ! public Document checkout() { ! return (Document) document.clone(); ! } ! ! /** ! * Accepts the changes from the document. If possible, rewrites ! * the content. Changes are synchronized but not checked; if two ! * concurrent threads make different changes, the last one to call ! * checkin() will win. This effectively gives the process a ! * transaction isolation level equivalent to TRANSACTION_READ_COMMITTED. ! */ ! public void checkin(Document document) { ! this.document = document; ! ! synchronized (url) { ! OutputStream outputStream = null; ! try { ! if ("file".equals(url.getProtocol())) { ! outputStream = new FileOutputStream(url.getFile()); ! } else { ! // Try to set "doOutput", may not work ! URLConnection connection = url.openConnection(); ! connection.setDoOutput(true); ! outputStream = connection.getOutputStream(); ! } ! new XMLOutputter(" ", true).output(document, outputStream); ! outputStream.flush(); ! outputStream.close(); ! } catch (IOException e) { ! e.printStackTrace(); ! } ! } // synchronized ! } } --- 20,33 ---- package org.xorm.datastore.xml; import java.net.URL; /** ! * Generic abstract base class for XML document holders * ! * @author Dan Checkoway */ ! public interface DocumentHolder { ! void setURL(URL url); ! Object checkout(); ! void checkin(Object document); } Index: XMLConnectionInfo.java =================================================================== RCS file: /cvsroot/xorm/xorm/src/org/xorm/datastore/xml/XMLConnectionInfo.java,v retrieving revision 1.2 retrieving revision 1.2.6.1 diff -C2 -d -r1.2 -r1.2.6.1 *** XMLConnectionInfo.java 17 Dec 2002 17:51:09 -0000 1.2 --- XMLConnectionInfo.java 8 Jun 2006 17:00:50 -0000 1.2.6.1 *************** *** 27,47 **** public class XMLConnectionInfo extends ConnectionInfo { - private DocumentHolder documentHolder; - - private DocumentHolder getDocumentHolder() { - if (documentHolder == null) { - try { - URL url = new URL(getConnectionURL()); - documentHolder = new DocumentHolder(url); - } catch (MalformedURLException e) { - // TODO - e.printStackTrace(); - } - } - return documentHolder; - } - public DatastoreDriver getDriver() { ! return new JDOMDocumentDriver(getDocumentHolder()); } } --- 27,47 ---- public class XMLConnectionInfo extends ConnectionInfo { public DatastoreDriver getDriver() { ! try { ! URL url = new URL(getConnectionURL()); ! /* ! if (use JDOM) { ! return new JDOMDocumentDriver(url); ! } ! else if (use W3C) { ! */ ! return new W3CDocumentDriver(url); ! /* ! } ! */ ! } catch (MalformedURLException e) { ! // TODO ! throw new RuntimeException(e); ! } } } Index: JDOMDocumentDriver.java =================================================================== RCS file: /cvsroot/xorm/xorm/src/org/xorm/datastore/xml/JDOMDocumentDriver.java,v retrieving revision 1.9 retrieving revision 1.9.2.1 diff -C2 -d -r1.9 -r1.9.2.1 *** JDOMDocumentDriver.java 8 Feb 2006 17:26:28 -0000 1.9 --- JDOMDocumentDriver.java 8 Jun 2006 17:00:50 -0000 1.9.2.1 *************** *** 21,24 **** --- 21,25 ---- import java.io.IOException; + import java.net.URL; import java.util.ArrayList; import java.util.Collection; *************** *** 49,53 **** * reference. * ! * This class relies on the transactional mechanics of the DocumentHolder * class. At the beginning of each transaction, it acquires a document * by calling checkout(); upon commit (but not rollback) it calls --- 50,54 ---- * reference. * ! * This class relies on the transactional mechanics of the JDOMDocumentHolder * class. At the beginning of each transaction, it acquires a document * by calling checkout(); upon commit (but not rollback) it calls *************** *** 57,61 **** */ public class JDOMDocumentDriver implements DatastoreDriver { ! private DocumentHolder documentHolder; private Document document; private boolean readOnly; --- 58,62 ---- */ public class JDOMDocumentDriver implements DatastoreDriver { ! private JDOMDocumentHolder documentHolder; private Document document; private boolean readOnly; *************** *** 65,70 **** * Sets the data source, which must be an instance of DocumentHolder. */ ! public JDOMDocumentDriver(DocumentHolder documentHolder) { ! this.documentHolder = documentHolder; } --- 66,72 ---- * Sets the data source, which must be an instance of DocumentHolder. */ ! public JDOMDocumentDriver(URL url) { ! documentHolder = new JDOMDocumentHolder(); ! documentHolder.setURL(url); } *************** *** 73,77 **** */ public void begin(boolean readOnly) { ! document = documentHolder.checkout(); this.readOnly = readOnly; onlyDidReads = true; --- 75,79 ---- */ public void begin(boolean readOnly) { ! document = (Document)documentHolder.checkout(); this.readOnly = readOnly; onlyDidReads = true; |