/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* $Id: XMLResourceImpl.java 566457 2007-08-16 01:04:02Z vgritsenko $
*/
package org.apache.xindice.client.xmldb.resources;
import org.apache.xindice.core.FaultCodes;
import org.apache.xindice.xml.SymbolTable;
import org.apache.xindice.xml.TextWriter;
import org.apache.xindice.xml.dom.DOMParser;
import org.apache.xindice.xml.dom.DocumentImpl;
import org.apache.xindice.xml.sax.SAXEventGenerator;
import org.apache.xindice.xml.sax.SetContentHandler;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xmldb.api.base.ErrorCodes;
import org.xmldb.api.base.XMLDBException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.StringReader;
/**
* XMLResourceImpl provides an implementation to handle XML resources
* and convert easily between Text, DOM or SAX presentations.
*
* @version $Revision: 566457 $, $Date: 2007-08-15 21:04:02 -0400 (Wed, 15 Aug 2007) $
*/
public class XMLResourceImpl implements org.xmldb.api.modules.XMLResource {
private static final SAXParserFactory saxFactory;
static {
saxFactory = SAXParserFactory.newInstance();
saxFactory.setNamespaceAware(true);
}
/**
* This is a SAX feature that controls how namespaces are reported in SAX.
* By default this feature is <em>on</em>.
*
* @see <a href="http://sax.sourceforge.net/?selected=namespaces">sax.sourceforge.net/?selected=namespaces</a>
*/
public static final String SAX_NAMESPACES_FEATURE
= SAXEventGenerator.SAX_NAMESPACES_FEATURE;
/**
* This is a SAX feature that controls how namespaces are reported in SAX.
* By default this feature is <em>off</em>.
*
* @see <a href="http://sax.sourceforge.net/?selected=namespaces">sax.sourceforge.net/?selected=namespaces</a>
*/
public static final String SAX_NAMESPACE_PREFIXES_FEATURE
= SAXEventGenerator.SAX_NAMESPACE_PREFIXES_FEATURE;
protected String id;
protected String documentId;
protected org.xmldb.api.base.Collection collection;
protected String content;
private SymbolTable symbols;
private byte[] bytes;
/*
* State of the SAX_NAMESPACES_FEATURE. True indicates namespace URIs and unprefixed local
* names for element and attribute names will be available.
*
* For SAX2 the default is true.
*/
private boolean hasSaxNamespaces = true;
/*
* State of the SAX_NAMESPACE_PREFIXES_FEATURE. True indicates XML 1.0 names (with prefixes)
* and attributes (including xmlns* attributes) will be available.
*
* For SAX2 the default is off.
*/
private boolean hasSaxNamespacesPrefixes;
/**
* Constructor for the XMLResourceImpl object
*
* @param id The unique id associated with this resource
* @param collection the parent collection for the resource
*/
public XMLResourceImpl(String id, org.xmldb.api.base.Collection collection) {
this(id, id, collection, null);
}
/**
* Constructor for the XMLResourceImpl object
*
* @param id The unique id associated with this resource
* @param documentId The parent document id associated with this resource
* @param collection the parent collection for the resource
*/
public XMLResourceImpl(String id, String documentId,
org.xmldb.api.base.Collection collection) {
this(id, documentId, collection, null);
}
/**
* Constructor for the XMLResourceImpl object
*
* @param id The unique id associated with this resource
* @param collection the parent collection for the resource
* @param content the content to associate with the resource
*/
public XMLResourceImpl(String id, org.xmldb.api.base.Collection collection,
String content) {
this(id, id, collection, content);
}
/**
* Constructor for the XMLResourceImpl object
*
* @param id The unique id associated with this resource
* @param documentId The parent document id associated with this resource
* @param collection the parent collection for the resource
* @param content the content to associate with the resource
*/
public XMLResourceImpl(String id, String documentId,
org.xmldb.api.base.Collection collection, String content) {
this.collection = collection;
this.id = id;
this.documentId = documentId;
this.content = content;
}
/**
* Constructor for the XMLResourceImpl object used in conjunction with
* Wire Compression
*
* @param id The unique id associated with this resource
* @param documentId The document identifier this resource belongs to
* @param collection The parent collection for the resource
* @param syms The collection's symbol table
* @param bytes The content to associate with the resource
*/
public XMLResourceImpl(String id, String documentId,
org.xmldb.api.base.Collection collection, SymbolTable syms, byte[] bytes) {
this.collection = collection;
this.id = id;
this.documentId = documentId;
this.symbols = syms;
this.bytes = bytes;
}
/**
* Constructor for the XMLResourceImpl object used in conjunction with
* Wire Compression
*
* @param id The unique id associated with this resource
* @param collection the parent collection for the resource
* @param syms The collection's symbol table
* @param bytes the content to associate with the resource
*/
public XMLResourceImpl(String id, org.xmldb.api.base.Collection collection,
SymbolTable syms, byte[] bytes) {
this(id, id, collection, syms, bytes);
}
/**
* Allows SAX feature to be set for the SAX that is generated by
* getContentAsSAX.
*
* @param feature feature name. Currently supported features are namespace
* reporting features described in the specification.
* @param value turn feature on or off.
* @see <a href="http://sax.sourceforge.net/?selected=namespaces">sax.sourceforge.net/?selected=namespaces</a>
*/
public void setSAXFeature(String feature, boolean value) {
if (SAX_NAMESPACES_FEATURE.equals(feature)) {
hasSaxNamespaces = value;
} else if (SAX_NAMESPACE_PREFIXES_FEATURE.equals(feature)) {
hasSaxNamespacesPrefixes = value;
}
}
/**
* Retrieves whether a SAX feature will be active for the
* SAX generated by the getContentAsSAX() method.
*
* @param feature feature name. Currently supported features are namespace
* reporting features described in the specification
* @return whether the feature is on or off
* @see <a href="http://sax.sourceforge.net/?selected=namespaces">sax.sourceforge.net/?selected=namespaces</a>
* @noinspection SimplifiableIfStatement
*/
public boolean getSAXFeature(String feature) {
if (SAX_NAMESPACES_FEATURE.equals(feature)) {
return hasSaxNamespaces;
} else if (SAX_NAMESPACE_PREFIXES_FEATURE.equals(feature)) {
return hasSaxNamespacesPrefixes;
} else {
return false;
}
}
/**
* Returns the unique id for the parent document to this <code>Resource</code>
* or null if the <code>Resource</code> does not have a parent document.
*
* @return the id for the parent document of this <code>Resource</code> or
* null if there is no parent document for this <code>Resource</code>.
* @exception XMLDBException
*/
public String getDocumentId() throws XMLDBException {
return documentId;
}
/**
* Sets the Content attribute of the XMLResourceImpl object. The value being
* set must be String object containing well formed XML text.
*
* @param value The new Content value
* @exception XMLDBException
*/
public void setContent(Object value) throws XMLDBException {
if (value == null) {
throw new XMLDBException(ErrorCodes.INVALID_RESOURCE);
} else if (value instanceof String) {
this.content = (String) value;
this.bytes = null;
} else {
throw new XMLDBException(ErrorCodes.WRONG_CONTENT_TYPE);
}
}
/**
* Sets the content of the resource from a DOM Node.
*
* @param content Node containing the new content.
* @exception XMLDBException
*/
public void setContentAsDOM(Node content) throws XMLDBException {
if (content != null) {
this.content = TextWriter.toString(content);
this.bytes = null;
} else {
throw new XMLDBException(ErrorCodes.INVALID_RESOURCE);
}
}
/**
* setContentAsSAX returns a SAX ContentHandler that can be used to set the
* content of the resource.
*
* @return The ContentHandler that is used to insert data into the database.
* @exception XMLDBException
*/
public ContentHandler setContentAsSAX() throws XMLDBException {
return new SetContentHandler(this);
}
/**
* Gets the parent Collection instance for this resource
*
* @return The ParentCollection value
* @exception XMLDBException
*/
public org.xmldb.api.base.Collection getParentCollection() throws XMLDBException {
return collection;
}
/**
* Returns the resource type for this Resource.
* <p />
* XML:DB defined resource types are: <p />
* XMLResource - all XML data stored in the database<br />
* BinaryResource - Binary blob data stored in the database<br />
*
* @return the resource type for the Resource.
* @exception XMLDBException
*/
public String getResourceType() throws XMLDBException {
return RESOURCE_TYPE;
}
/**
* Gets the Id attribute of the XMLResourceImpl object
*
* @return The Id value
* @exception XMLDBException
*/
public String getId() throws XMLDBException {
return id;
}
/**
* Gets the content of the XMLResourceImpl object
*
* @return The Content value
* @exception XMLDBException
*/
public Object getContent() throws XMLDBException {
if (bytes != null) {
DocumentImpl doc = new DocumentImpl(bytes, symbols, null);
return TextWriter.toString(doc);
} else {
return content;
}
}
/**
* Returns the content of the resource as a DOM Node.
*
* @return The content as a DOM node
* @exception XMLDBException
*/
public Node getContentAsDOM() throws XMLDBException {
try {
if (bytes != null) {
return new DocumentImpl(bytes, symbols, null);
} else {
return DOMParser.toDocument(content);
}
} catch (Exception e) {
throw FaultCodes.createXMLDBException(e);
}
}
/**
* getContentAsSAX enables retrieving of the content via the use of a SAX
* ContentHandler.
*
* @param handler The ContentHandler to use.
* @exception XMLDBException
*/
public void getContentAsSAX(ContentHandler handler) throws XMLDBException {
// TODO: should probably use JAXP
try {
if (bytes != null) {
SAXEventGenerator events = new SAXEventGenerator(symbols, bytes);
events.setFeature(SAX_NAMESPACES_FEATURE, hasSaxNamespaces);
events.setFeature(SAX_NAMESPACE_PREFIXES_FEATURE, hasSaxNamespacesPrefixes);
events.setContentHandler(handler);
if (handler instanceof ErrorHandler) {
events.setErrorHandler((ErrorHandler) handler);
}
events.start();
} else if (content != null) {
SAXParser sp = saxFactory.newSAXParser();
XMLReader xr = sp.getXMLReader();
xr.setFeature(SAX_NAMESPACES_FEATURE, hasSaxNamespaces);
xr.setFeature(SAX_NAMESPACE_PREFIXES_FEATURE, hasSaxNamespacesPrefixes);
xr.setContentHandler(handler);
if (handler instanceof ErrorHandler) {
xr.setErrorHandler((ErrorHandler) handler);
}
xr.parse(new InputSource(new StringReader(content)));
}
} catch (Exception e) {
throw FaultCodes.createXMLDBException(e);
}
}
public void setId(String name) {
this.id = name;
}
}