Package org.xorm.datastore.xml

Source Code of org.xorm.datastore.xml.JDOMDocumentDriver

/*
    $Header: /cvsroot/xorm/xorm/src/org/xorm/datastore/xml/JDOMDocumentDriver.java,v 1.8 2003/08/14 05:46:41 wbiggs 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.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.jdom.Document;
import org.jdom.Element;

/**
* 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 Wes Biggs
*/
public class JDOMDocumentDriver 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 JDOMDocumentDriver(DocumentHolder documentHolder) {
  this.documentHolder = documentHolder;
    }

    /**
     * Begins a transaction by calling checkout on the DocumentHolder.
     */
    public void begin(boolean readOnly) {
  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 = new Element(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.getParent() == null && !element.isRootElement()) {
           document.getRootElement().addContent(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);
  element.detach();
  // 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.getRootElement(), 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;
    xmlResults =  parent.getChildren(table.getName());
      }
  }

  // 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.getAttributeValue(path.substring(1));
  }

  // text node
  if ("text()".equals(path)) {
      return element.getTextTrim();
  }

  if (".".equals(path)) {
      return element;
  } else if ("..".equals(path)) {
      return element.getParent();
  } else {
      return element.getChild(path);
  }
    }

    /**
     * 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)) {
    element = element.getParent();
      } else {
    Element parent = element;
    element = element.getChild(path);
    if (create && (element == null)) {
        element = new Element(path);
        parent.addContent(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("@")) {
      element.setAttribute(path.substring(1), (String) value);
  } else if ("text()".equals(path)) {
      element.setText((String) value);
  } else if (".".equals(path)) {
      // self-reference (primary key) -- ignore
  } else if ("..".equals(path)) {
      Element parent = (Element) value;
      element.detach();
      parent.addContent(element);
  } else {
      // Child reference
      element.addContent((Element) value);
  }
    }

}
TOP

Related Classes of org.xorm.datastore.xml.JDOMDocumentDriver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.