// You can redistribute this software and/or modify it under the terms of
// the Ozone Library License version 1 published by ozone-db.org.
//
// The original code and portions created by SMB are
// Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
//
// $Id: XMLResourceImpl.java,v 1.1 2001/12/18 11:03:24 per_nyfelt Exp $
package org.ozoneDB.xml.cli.resources;
import java.io.StringReader;
import java.io.StringWriter;
import org.ozoneDB.ExternalDatabase;
import org.ozoneDB.ExternalTransaction;
import org.ozoneDB.xml.core.XMLCollection;
import org.ozoneDB.xml.util.XMLContainer;
import org.w3c.dom.Node;
import org.w3c.dom.Document;
import org.apache.xerces.parsers.DOMParser;
//import org.apache.xerces.parsers.SAXParser;
import javax.xml.parsers.SAXParser;
import org.xml.sax.helpers.ParserAdapter;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
//import org.xml.sax.helpers.XMLReaderFactory;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.ErrorCodes;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.XMLResource;
import org.apache.xml.serialize.XMLSerializer;
import org.apache.xml.serialize.OutputFormat;
/**
* This is a database persistent XML class for XML:DB, possible of
* returning XML content back as DOM, SAX or String. Performance is
* best using DOM. Please note that getContent() is overridden to
* return a <code>String</code> back and can always be cast to a String.
*
* @author <a href="http://www.smb-tec.com">SMB</a>, Per Nyfelt
* @version $Revision: 1.1 $
*/
public class XMLResourceImpl implements XMLResource {
//
// data
//
// the SAX parser we use in setContent
private final SAXParserFactory parserFactory = new org.apache.xerces.jaxp.SAXParserFactoryImpl();
private ExternalDatabase database;
// the XML document this class operates on
private XMLContainer container;
// the Collection this resource resides in
private Collection collection;
// since there is no setId() in the interface we have to get the id in the construction
private String id;
public XMLResourceImpl( String id, ExternalDatabase database, Collection collection,
XMLContainer container ) {
System.out.println("XMLResourceImpl CREATED ***********");
this.database = database;
this.container = container;
this.collection = collection;
this.id = id;
}
/**
* Returns the <code>Collection</code> instance that this resource is
* associated with.
*
* @return the collection associated with the resource.
*/
public Collection getParentCollection() throws XMLDBException {
return collection;
}
/**
* Returns the unique id for this Resource or null if the resource has
* not yet been given one.
*
* @return the id for the Resource or null if no id exists.
*/
public String getId() throws XMLDBException {
return id;
}
/**
* Sets the content of the <code>Resource</code> using a either a
* String or a DOM Node as the source.
*
* @param content The new content value
*/
public void setContent( Object value ) throws XMLDBException {
if (value instanceof String) {
ExternalTransaction tx = database.newTransaction();
// we assume it's a valid XML doc and parse it
try {
StringReader in = new StringReader((String)value);
InputSource source = new InputSource(in);
SAXParser parser = parserFactory.newSAXParser();
ParserAdapter adapter = new ParserAdapter( parser.getParser() );
tx.begin();
adapter.setContentHandler( container.storeSAX() );
adapter.parse( source );
tx.commit();
}
catch (SAXException e) {
try {
if (tx.getStatus() == tx.STATUS_ACTIVE)
tx.rollback();
throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, e.getMessage());
}
catch (Exception rollbackException) {
throw new XMLDBException(ErrorCodes.VENDOR_ERROR, rollbackException.toString());
}
}
catch (Exception e) {
try {
if (tx.getStatus() == tx.STATUS_ACTIVE)
tx.rollback();
throw new XMLDBException(ErrorCodes.VENDOR_ERROR, e.getMessage());
}
catch (Exception rollbackException) {
throw new XMLDBException(ErrorCodes.VENDOR_ERROR, rollbackException.toString());
}
}
}
else if (value instanceof Node) {
setContentAsDOM((Node)value);
}
else
throw new XMLDBException( ErrorCodes.VENDOR_ERROR, ErrorCodes.UNKNOWN_RESOURCE_TYPE );
}
/**
* Returns a String representation of the XML content
* usage exampel : <BR/>
* String content = (String)xmlResource.getContent(); <BR/>
* @return a String representation of the XML content
*/
public Object getContent() throws XMLDBException {
try {
return toString( "xml", "UTF-8", true );
}
catch (Exception e) {
throw new XMLDBException( ErrorCodes.VENDOR_ERROR, e.getMessage());
}
}
/**
* Returns the resource type for this Resource.
*
* @return the resource type for the Resource.
*/
public String getResourceType() throws XMLDBException {
return XMLResource.RESOURCE_TYPE;
}
/**
* Returns the content of the <code>Resource</code> as a DOM Node.
*
* @return The XML content as a DOM <code>Node</code>
*/
public Node getContentAsDOM() throws XMLDBException {
ExternalTransaction tx = database.newTransaction();
try {
tx.begin();
DocumentBuilderFactory builderFactory = new org.apache.xerces.jaxp.DocumentBuilderFactoryImpl();
DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
Document doc = container.extractDOM(documentBuilder.newDocument());
tx.commit();
return doc;
}
catch (Exception e) {
try {
if (tx.getStatus() == tx.STATUS_ACTIVE)
tx.rollback();
throw new XMLDBException( ErrorCodes.VENDOR_ERROR, e.getMessage());
}
catch (Exception rollbackException) {
throw new XMLDBException(ErrorCodes.VENDOR_ERROR, rollbackException.toString());
}
}
}
/**
* Sets the content of the <code>Resource</code> using a DOM Node as the
* source.
*
* @param content The new content value
*/
public void setContentAsDOM( Node content ) throws XMLDBException {
ExternalTransaction tx = database.newTransaction();
try {
if (content == null) {
System.out.println("XMLResourceImpl.setContentAsDOM() - Content is null");
throw new XMLDBException(ErrorCodes.INVALID_RESOURCE);
}
if (content instanceof Document) {
Document doc = (Document)content;
tx.begin();
container.storeDOM(doc);
tx.commit();
}
else {
System.out.println("Cannot store Nodes right now, must be a Document");
}
}
catch (Exception e) {
e.printStackTrace();
try {
System.out.println("XMLResourceImpl.setContentAsDOM() - Transaction status is " + tx.getStatus());
if (tx.getStatus() == tx.STATUS_ACTIVE)
tx.rollback();
throw new XMLDBException( ErrorCodes.VENDOR_ERROR, e.getMessage());
}
catch (Exception rollbackException) {
throw new XMLDBException(ErrorCodes.VENDOR_ERROR, rollbackException.getMessage());
}
}
}
/**
* Allows you to use a <code>ContentHandler</code> to parse the XML data from
* the database for use in an application.
*
* @param handler the SAX <code>ContentHandler</code> to use to handle the
* <code>Resource</code> content.
*/
public void getContentAsSAX( ContentHandler handler ) throws XMLDBException {
ExternalTransaction tx = database.newTransaction();
try {
tx.begin();
container.extractSAX(handler);
tx.commit();
}
catch (Exception e) {
try {
if (tx.getStatus() == tx.STATUS_ACTIVE)
tx.rollback();
throw new XMLDBException( ErrorCodes.VENDOR_ERROR, e.getMessage());
}
catch (Exception rollbackException) {
throw new XMLDBException(ErrorCodes.VENDOR_ERROR, rollbackException.toString());
}
}
}
/**
* Sets the content of the <code>Resource</code> using a SAX
* <code>ContentHandler</code>.
*
* @return a SAX <code>ContentHandler</code> that can be used to add content
* into the <code>Resource</code>.
*/
public ContentHandler setContentAsSAX() throws XMLDBException {
ExternalTransaction tx = database.newTransaction();
try {
tx.begin();
ContentHandler handler = container.storeSAX();
tx.commit();
return handler;
}
catch (Exception e) {
try {
if (tx.getStatus() == tx.STATUS_ACTIVE)
tx.rollback();
throw new XMLDBException( ErrorCodes.VENDOR_ERROR, e.getMessage());
}
catch (Exception rollbackException) {
throw new XMLDBException(ErrorCodes.VENDOR_ERROR, rollbackException.toString());
}
}
}
/** returns a String representation of the Document with the method to be used ,
* the encoding type specified and whether to indent or not <br/>
* Example: String content = toString( "xml", "UTF-8", true );
*
*/
private String toString(String type, String encoding, boolean indenting) throws Exception {
int depth = -1;
ExternalTransaction tx = database.newTransaction();
tx.begin();
try {
StringWriter writer = new StringWriter();
XMLSerializer serializer = new XMLSerializer( writer, new OutputFormat(type, encoding, indenting) );
ContentHandler handler = serializer.asContentHandler();
container.extractSAX( handler, null, depth );
writer.flush();
tx.commit();
return writer.toString();
}
catch (Exception e) {
if (tx.getStatus() == tx.STATUS_ACTIVE)
tx.rollback();
throw e;
}
}
}