vgritsenko 2003/08/05 21:04:28
Modified: java/src/org/apache/xindice/client/xmldb/xmlrpc
CollectionImpl.java
Log:
rinse & repeat. Also, make logger final
Revision Changes Path
1.29 +655 -687
xml-xindice/java/src/org/apache/xindice/client/xmldb/xmlrpc/CollectionImpl.java
Index: CollectionImpl.java
===================================================================
RCS file:
/home/cvs/xml-xindice/java/src/org/apache/xindice/client/xmldb/xmlrpc/CollectionImpl.java,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -r1.28 -r1.29
--- CollectionImpl.java 5 Aug 2003 08:47:00 -0000 1.28
+++ CollectionImpl.java 6 Aug 2003 04:04:28 -0000 1.29
@@ -59,13 +59,6 @@
* $Id$
*/
-import java.io.StringReader;
-import java.net.MalformedURLException;
-import java.util.Hashtable;
-import java.util.Vector;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xindice.client.xmldb.ResourceSetImpl;
@@ -80,6 +73,7 @@
import org.apache.xindice.xml.dom.DOMParser;
import org.apache.xmlrpc.XmlRpc;
import org.apache.xmlrpc.XmlRpcClient;
+
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xmldb.api.base.Collection;
@@ -89,6 +83,12 @@
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.XMLResource;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.StringReader;
+import java.net.MalformedURLException;
+import java.util.Hashtable;
+import java.util.Vector;
+
/**
* Implementation of XML:DB's <code>Collection</code> interface using
* XML-RPC to interact with database server
@@ -97,683 +97,651 @@
* @author <a href="mailto:[EMAIL PROTECTED]">Kimbro Staken</a>
*/
public class CollectionImpl extends XindiceCollection {
-
- private static Log log =
LogFactory.getLog("org.apache.xindice.client.xmldb.xmlrpc");
-
- /* path to XML-RPC service on database */
- private static String XINDICE_SERVICE_LOCATION = "/xindice/";
-
- /* host and port number of server */
- private String hostPort;
-
- /* location of the XML-RPC service in the web server */
- private String serviceLocation;
-
- /* SAX parser the XML-RPC service will use */
- private String xmlrpcDriver;
-
- /* the XML-RPC client stub, connected to server */
- private XmlRpcClient client = null;
-
- /**
- * Creates new <code>CollectionImpl</code> instance representing
connection
- * to server collection.
- *
- * @param hostPort hostname and port number in <code>host:port</code>
format.
- * Port no is optional, in which case HTTP default is assumed.
- * @param serviceLocation is the path in the web server's namespace
where
- * the XML-RPC service is mounted. It is <code>null</code>
unless
- * the <code>service-location</code> property of
- * <code>org.apache.xindice.client.xmlrpc.DatabaseImpl</code>
- * is set.
- * @param collPath is the name of the collection to open.
- * @exception XMLDBException thrown if a connection could not be
established,
- * because of URL syntax errors, or connection failure, or
if no
- * collection with path <code>collPath</code> could be
located.
- */
- public CollectionImpl(String hostPort, String serviceLocation, String
xmlrpcDriver, String collPath) throws XMLDBException {
- super(collPath);
- this.hostPort = hostPort;
- this.serviceLocation = serviceLocation;
- this.xmlrpcDriver = xmlrpcDriver;
-
- XmlRpc.setEncoding("UTF8");
-
- /*
- * Determine the SAXparser the xmlrpc client will use.
- * In priority order:
- * DatabaseImpl xmlrpc-driver property
- * (passed in the xmlrpcDriver parameter)
- * System property "xindice.xmlrpc.driver"
- * Default value "xerces"
- */
- if (xmlrpcDriver == null) {
- xmlrpcDriver =
System.getProperty("xindice.xmlrpc.driver");
- }
- if (xmlrpcDriver == null) {
- xmlrpcDriver = "xerces";
- }
- XmlRpc.setKeepAlive(true);
- try {
- XmlRpc.setDriver(xmlrpcDriver);
- }
- catch (Exception e) {
- throw new XMLDBException(ErrorCodes.VENDOR_ERROR,
"Xerces needed", e);
- }
-
- /*
- * Determine the path in the web server to the XML-RPC service.
- * In priority order:
- * DatabaseImpl service-location property
- * (passed in the serviceLocation parameter)
- * System property "xindice.xmlrpc.service-location"
- * Default value "/xindice/"
- */
- if (serviceLocation == null) {
- serviceLocation =
System.getProperty("xindice.xmlrpc.service-location");
- }
- if (serviceLocation == null) {
- serviceLocation = XINDICE_SERVICE_LOCATION;
- }
-
- if (!serviceLocation.startsWith("/")) {
- serviceLocation = "/" + serviceLocation;
- }
- if (!serviceLocation.endsWith("/")) {
- serviceLocation = serviceLocation + "/";
- }
-
- log.debug("serviceLocation=<" + serviceLocation + ">");
- String xmlrpcURI = "http://" + hostPort + serviceLocation;
-
- try {
- client = new XmlRpcClient(xmlrpcURI);
-
- /* Just check the collection does actually exist */
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- String exists = (String)
runRemoteCommand("GetCollectionConfiguration", params);
- if (!"yes".equals(exists)) {
-
- throw new
XMLDBException(ErrorCodes.NO_SUCH_COLLECTION, "Collection not found: " +
collPath);
- }
- }
- catch (MalformedURLException e) {
- client = null;
- throw new XMLDBException(ErrorCodes.INVALID_URI, e);
- }
- catch(XMLDBException x){
-
- throw x; // propagate any xmldb exception.
- }
- catch (Exception e) {
- client = null;
- throw new XMLDBException(ErrorCodes.NO_SUCH_COLLECTION,
"Collection not found: " + collPath, e);
- }
- }
-
- /**
- * Submits a command for RPC to database server
- *
- * @param cmdName command name
- * @param params hashtable containing named parameters to send to server
- * @return the return value from the server. Type of return value
depends on
- * command.
- *
- * @exception Exception thrown if XML-RPC reports an exception.
- */
- private Object runRemoteCommand(String cmdName, Hashtable params)
throws Exception {
-
- params.put(RPCMessageInterface.MESSAGE_PARAM, cmdName);
-
- Vector v = new Vector();
- v.add(params);
- return ((Hashtable) client.execute("run",
v)).get(RPCDefaultMessage.RESULT);
- }
-
- /**
- * Retrieves a <code>Resource</code> from the database. If the
- * <code>Resource</code> could not be
- * located a null value will be returned.
- *
- * @param id the unique id for the requested resource.
- * @return The retrieved <code>Resource</code> instance.
- * @exception XMLDBException with expected error codes.<br />
- * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
- * specific errors that occur.<br />
- * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
- * method has been called on the <code>Collection</code><br />
- */
- public Resource getResource(String id) throws XMLDBException {
-
- checkOpen();
- try {
-
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- params.put(RPCDefaultMessage.NAME, id);
- params.put(RPCDefaultMessage.COMPRESSED, "true");
-
- Object result = runRemoteCommand("GetDocument", params);
- /*
- * If we get a Hashtable back then the result is
compressed.
- */
- if (result instanceof Hashtable) {
- Hashtable compressed = (Hashtable) result;
- SymbolDeserializer symbolDeserial = new
SymbolDeserializer();
- return new XMLResourceImpl(id, id, this,
symbolDeserial.getSymbols(compressed), (byte[]) compressed.get("document"));
- }
- else {
- return new XMLResourceImpl(id, (String) result,
this);
- }
-
- }
- catch (Exception e) {
- return null;
- }
- }
-
- /**
- * Returns the number of resources currently stored in this collection
or 0
- * if the collection is empty.
- *
- * @return the number of resource in the collection.
- * @exception XMLDBException with expected error codes.<br />
- * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
- * specific errors that occur.<br />
- * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
- * method has been called on the <code>Collection</code><br />
- */
- public int getResourceCount() throws XMLDBException {
-
- checkOpen();
- try {
-
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- return ((Integer) runRemoteCommand("GetDocumentCount",
params)).intValue();
- }
- catch(XMLDBException x){
-
- throw x; // propagate any xmldb exception.
- }
- catch (Exception e) {
-
- throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e);
- }
- }
-
- /**
- * Stores the provided resource into the database. If the resource does
not
- * already exist it will be created. If it does already exist it will be
- * updated.
- *
- * @param res the resource to store in the database.
- * @exception XMLDBException with expected error codes.<br />
- * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
- * specific errors that occur.<br />
- * <code>ErrorCodes.INVALID_RESOURCE</code> if the
<code>Resource</code> is
- * not valid.
- * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
- * method has been called on the <code>Collection</code><br />
- */
- public void storeResource(Resource res) throws XMLDBException {
-
- if (!(res instanceof XMLResource)) {
-
- throw new XMLDBException(ErrorCodes.INVALID_RESOURCE,
"Only XML resources supported");
- }
-
- if (res.getContent() == null) {
-
- throw new XMLDBException(ErrorCodes.INVALID_RESOURCE,
"no resource data");
- }
- checkOpen();
- try {
-
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- params.put(RPCDefaultMessage.NAME, res.getId());
- params.put(RPCDefaultMessage.DOCUMENT,
res.getContent());
-
- String name = (String)
runRemoteCommand("InsertDocument", params);
- ((XMLResourceImpl) res).setId(name);
-
- }
- catch(XMLDBException x){
-
- throw x; // propagate any xmldb exception.
- }
- catch (Exception e) {
-
- throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e);
- }
- }
-
- /* see superclass for documentation */
- public boolean isOpen() {
-
- return (client != null);
- }
-
- /* see superclass for documentation */
- public String getURI() {
-
- return "xmldb:" + DatabaseImpl.DRIVER_NAME + "://" + hostPort +
collPath;
- }
-
- /**
- * Returns a <code>Collection</code> instance for the requested child
collection
- * if it exists.
- *
- * @param name the name of the child collection to retrieve.
- * @return the requested child collection or null if it couldn't be
found.
- * @exception XMLDBException with expected error codes.<br />
- * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
- * specific errors that occur.<br />
- * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
- * method has been called on the <code>Collection</code><br />
- */
- public Collection getChildCollection(String name) throws XMLDBException
{
-
- if (name.indexOf('/') != -1) {
-
- throw new XMLDBException(ErrorCodes.INVALID_COLLECTION);
- }
-
- try {
- return new CollectionImpl(hostPort, serviceLocation,
xmlrpcDriver, collPath + "/" + name);
- }
- catch (XMLDBException e) {
-
- if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) {
- // per getChildCollection contract, return null
if not found
- return null;
- }
-
- throw e;
- }
- }
-
- /**
- * Creates a new unique ID within the context of the
<code>Collection</code>
- *
- * @return the created id as a string.
- * @exception XMLDBException with expected error codes.<br />
- * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
- * specific errors that occur.<br />
- * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
- * method has been called on the <code>Collection</code><br />
- */
- public String createId() throws XMLDBException {
-
- checkOpen();
- try {
-
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- return (String) runRemoteCommand("CreateNewOID",
params);
- }
- catch(XMLDBException x){
-
- throw x; // propagate any xmldb exception.
- }
- catch (Exception e) {
-
- throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e);
- }
- }
-
- /**
- * Releases all resources consumed by the <code>Collection</code>.
- * The <code>close</code> method must
- * always be called when use of a <code>Collection</code> is complete.
It is
- * not safe to use a <code>Collection</code> after the
<code>close</code>
- * method has been called.
- *
- * @exception XMLDBException with expected error codes.<br />
- * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
- * specific errors that occur.<br />
- */
- public void close() throws org.xmldb.api.base.XMLDBException {
-
- client = null;
- }
-
- /**
- * Returns the parent collection for this collection or null if no
parent
- * collection exists.
- *
- * @return the parent <code>Collection</code> instance.
- * @exception XMLDBException with expected error codes.<br />
- * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
- * specific errors that occur.<br />
- * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
- * method has been called on the <code>Collection</code><br />
- */
- public Collection getParentCollection() throws XMLDBException {
-
- // If there's only one slash then it's the root.
- if (collPath.lastIndexOf("/") == 0) {
- return null;
- }
-
- try {
- return new CollectionImpl(hostPort, serviceLocation,
xmlrpcDriver, collPath.substring(0, collPath.lastIndexOf('/')));
- }
- catch (XMLDBException e) {
- if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) {
- // per getParentCollection contract, return
null if no parent
- return null;
- }
- throw e;
- }
- }
-
- /**
- * Removes the <code>Resource</code> from the database.
- *
- * @param res the resource to remove.
- * @exception XMLDBException with expected error codes.<br />
- * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
- * specific errors that occur.<br />
- * <code>ErrorCodes.INVALID_RESOURCE</code> if the
<code>Resource</code> is
- * not valid.<br />
- * <code>ErrorCodes.NO_SUCH_RESOURCE</code> if the
<code>Resource</code> is
- * not known to this <code>Collection</code>.
- * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
- * method has been called on the <code>Collection</code><br />
- */
- public void removeResource(Resource res) throws XMLDBException {
-
- if (!(res instanceof XMLResource)) {
-
- throw new XMLDBException(ErrorCodes.INVALID_RESOURCE,
"Only XML resources supported");
- }
-
- if (res.getId() == null) {
- throw new XMLDBException(ErrorCodes.VENDOR_ERROR, "This
resource is a query result and can " + "not be removed from the database.");
- }
-
- checkOpen();
- try {
-
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- params.put(RPCDefaultMessage.NAME, res.getId());
- runRemoteCommand("RemoveDocument", params);
- }
- catch(XMLDBException x){
-
- throw x; // propagate any xmldb exception.
- }
- catch (Exception e) {
- throw new XMLDBException(ErrorCodes.NO_SUCH_RESOURCE,
e);
- }
- }
-
- /**
- * Returns a list of collection names naming all child collections
- * of the current collection. If no child collections exist an empty
list is
- * returned.
- *
- * @return an array containing collection names for all child
- * collections.
- * @exception XMLDBException with expected error codes.<br />
- * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
- * specific errors that occur.<br />
- * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
- * method has been called on the <code>Collection</code><br />
- */
- public String[] listChildCollections() throws XMLDBException {
-
- checkOpen();
- try {
-
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- Vector list = (Vector)
runRemoteCommand("ListCollections", params);
-
- return (String[]) list.toArray(new String[list.size()]);
- }
- catch(XMLDBException x){
-
- throw x; // propagate any xmldb exception.
- }
- catch (Exception e) {
-
- throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e);
- }
- }
-
- /**
- * Returns the number of child collections under this
- * <code>Collection</code> or 0 if no child collections exist.
- *
- * @return the number of child collections.
- * @exception XMLDBException with expected error codes.<br />
- * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
- * specific errors that occur.<br />
- * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
- * method has been called on the <code>Collection</code><br />
- */
- public int getChildCollectionCount() throws XMLDBException {
-
- checkOpen();
- try {
-
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- Integer result = (Integer)
runRemoteCommand("GetCollectionCount", params);
- return result.intValue();
-
- }
- catch(XMLDBException x){
-
- throw x; // propagate any xmldb exception.
- }
- catch (Exception e) {
- throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e);
- }
- }
-
- /**
- * Returns a list of the ids for all resources stored in the collection.
- *
- * @return a string array containing the names for all
- * <code>Resource</code>s in the collection.
- * @exception XMLDBException with expected error codes.<br />
- * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
- * specific errors that occur.<br />
- * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
- * method has been called on the <code>Collection</code><br />
- */
- public String[] listResources() throws XMLDBException {
-
- checkOpen();
- try {
-
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- Vector list = (Vector)
runRemoteCommand("ListDocuments", params);
-
- return (String[]) list.toArray(new String[list.size()]);
- }
- catch(XMLDBException x){
-
- throw x; // propagate any xmldb exception.
- }
- catch (Exception e) {
-
- throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e);
- }
- }
-
- /* see superclass for documentation */
- public ResourceSet query(String name, String queryLang, String query,
Hashtable nsMap) throws XMLDBException {
-
- checkOpen();
- try {
-
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- params.put(RPCDefaultMessage.TYPE, queryLang);
- params.put(RPCDefaultMessage.NAMESPACES, nsMap);
- params.put(RPCDefaultMessage.QUERY, query);
-
- if (name != null) {
-
- params.put(RPCDefaultMessage.NAME, name);
- }
-
- String result = (String) runRemoteCommand("Query",
params);
- DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
- dbf.setNamespaceAware(true);
- Document resultDoc = dbf.newDocumentBuilder().parse(new
InputSource(new StringReader(result)));
-
- ResourceSetImpl rs = new ResourceSetImpl(this,
resultDoc);
-
- return rs;
- }
- catch (Exception e) {
-e.printStackTrace();
- throw
FaultCodes.createXMLDBException(FaultCodes.QRY_PROCESSING_ERROR, "Query error",
e);
- }
- }
-
- /* see superclass for documentation */
- public Collection createCollection(String name) throws XMLDBException {
- return createCollection(name, null);
- }
-
- /* see superclass for documentation */
- public Collection createCollection(String name, Document configuration)
throws XMLDBException {
- checkOpen();
- try {
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- params.put(RPCDefaultMessage.NAME, name);
- if (configuration != null) {
- params.put(RPCDefaultMessage.CONFIGURATION,
TextWriter.toString(configuration));
- }
-
- runRemoteCommand("CreateCollection", params);
-
- return getChildCollection(name);
- }
- catch(XMLDBException x){
-
- throw x; // propagate any xmldb exception.
- }
- catch (Exception e) {
- throw new XMLDBException(ErrorCodes.INVALID_COLLECTION,
"Cannot create child collection", e);
- }
- }
-
- /* see superclass for documentation */
- public void removeCollection(String childName) throws XMLDBException {
-
- // todo: shortcut the call and fail immediatly if the collection
name is null or empty
-
- checkOpen();
- try {
-
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- params.put(RPCDefaultMessage.NAME, childName);
- String result = (String)
runRemoteCommand("RemoveCollection", params);
-
- if (!result.equals("yes")) {
-
- throw new
XMLDBException(ErrorCodes.INVALID_COLLECTION, "Cannot remove child collection["
+ childName + "]");
- }
- }
- catch(XMLDBException x){
-
- throw x; // propagate any xmldb exception.
- }
- catch (Exception e) {
-
- throw new XMLDBException(ErrorCodes.INVALID_COLLECTION,
"Cannot remove child collection[" + childName + "]", e);
- }
- }
-
- /* see superclass for documentation */
- public String[] listIndexers() throws XMLDBException {
- checkOpen();
- try {
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- Vector list = (Vector) runRemoteCommand("ListIndexers",
params);
-
- return (String[]) list.toArray(new String[list.size()]);
- }
- catch (Exception e) {
- throw FaultCodes.createXMLDBException(e);
- }
- }
-
- /* see superclass for documentation */
- public void createIndexer(Document configuration) throws XMLDBException
{
- checkOpen();
- try {
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- params.put(RPCDefaultMessage.CONFIGURATION,
TextWriter.toString(configuration));
-
- runRemoteCommand("CreateIndexer", params);
- }
- catch (Exception e) {
- throw FaultCodes.createXMLDBException(e);
- }
- }
-
- /* see superclass for documentation */
- public void dropIndexer(String name) throws XMLDBException {
- checkOpen();
- try {
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- params.put(RPCDefaultMessage.NAME, name);
-
- runRemoteCommand("RemoveIndexer", params);
- }
- catch (Exception e) {
- throw FaultCodes.createXMLDBException(e);
- }
- }
-
- /* see superclass for documentation */
- public void shutdown() throws XMLDBException {
- checkOpen();
- try {
- Hashtable params = new Hashtable();
-
- runRemoteCommand("Shutdown", params);
- }
- catch (Exception e) {
- throw FaultCodes.createXMLDBException(e);
- }
- }
-
- public MetaData getMetaData(String id) throws XMLDBException {
- checkOpen();
- try {
- Hashtable params = new Hashtable();
- params.put(RPCDefaultMessage.COLLECTION, collPath);
- if (id != null) {
- params.put(RPCDefaultMessage.NAME, id);
- }
- params.put(RPCDefaultMessage.COMPRESSED, "true");
-
- Object result = runRemoteCommand(id == null?
"GetCollectionMeta" : "GetDocumentMeta", params);
- Document metaDoc =
DOMParser.toDocument(result.toString());
- MetaData meta = new MetaData(id);
- meta.streamFromXML(metaDoc.getDocumentElement(), true);
- return meta;
- }
- catch (Exception e) {
- throw FaultCodes.createXMLDBException(e);
- }
- }
+
+ private static final Log log = LogFactory.getLog(CollectionImpl.class);
+
+ /* path to XML-RPC service on database */
+ private static String XINDICE_SERVICE_LOCATION = "/xindice/";
+
+ /* host and port number of server */
+ private String hostPort;
+
+ /* location of the XML-RPC service in the web server */
+ private String serviceLocation;
+
+ /* SAX parser the XML-RPC service will use */
+ private String xmlrpcDriver;
+
+ /* the XML-RPC client stub, connected to server */
+ private XmlRpcClient client = null;
+
+ /**
+ * Creates new <code>CollectionImpl</code> instance representing
connection
+ * to server collection.
+ *
+ * @param hostPort hostname and port number in <code>host:port</code>
format.
+ * Port no is optional, in which case HTTP default is assumed.
+ * @param serviceLocation is the path in the web server's namespace where
+ * the XML-RPC service is mounted. It is <code>null</code> unless
+ * the <code>service-location</code> property of
+ * <code>org.apache.xindice.client.xmlrpc.DatabaseImpl</code>
+ * is set.
+ * @param collPath is the name of the collection to open.
+ * @exception XMLDBException thrown if a connection could not be
established,
+ * because of URL syntax errors, or connection failure, or if
no
+ * collection with path <code>collPath</code> could be
located.
+ */
+ public CollectionImpl(String hostPort, String serviceLocation, String
xmlrpcDriver, String collPath) throws XMLDBException {
+ super(collPath);
+ this.hostPort = hostPort;
+ this.serviceLocation = serviceLocation;
+ this.xmlrpcDriver = xmlrpcDriver;
+
+ XmlRpc.setEncoding("UTF8");
+
+ /*
+ * Determine the SAXparser the xmlrpc client will use.
+ * In priority order:
+ * DatabaseImpl xmlrpc-driver property
+ * (passed in the xmlrpcDriver parameter)
+ * System property "xindice.xmlrpc.driver"
+ * Default value "xerces"
+ */
+ if (xmlrpcDriver == null) {
+ xmlrpcDriver = System.getProperty("xindice.xmlrpc.driver");
+ }
+ if (xmlrpcDriver == null) {
+ xmlrpcDriver = "xerces";
+ }
+ XmlRpc.setKeepAlive(true);
+ try {
+ XmlRpc.setDriver(xmlrpcDriver);
+ } catch (Exception e) {
+ throw new XMLDBException(ErrorCodes.VENDOR_ERROR, "Xerces
needed", e);
+ }
+
+ /*
+ * Determine the path in the web server to the XML-RPC service.
+ * In priority order:
+ * DatabaseImpl service-location property
+ * (passed in the serviceLocation parameter)
+ * System property "xindice.xmlrpc.service-location"
+ * Default value "/xindice/"
+ */
+ if (serviceLocation == null) {
+ serviceLocation =
System.getProperty("xindice.xmlrpc.service-location");
+ }
+ if (serviceLocation == null) {
+ serviceLocation = XINDICE_SERVICE_LOCATION;
+ }
+
+ if (!serviceLocation.startsWith("/")) {
+ serviceLocation = "/" + serviceLocation;
+ }
+ if (!serviceLocation.endsWith("/")) {
+ serviceLocation = serviceLocation + "/";
+ }
+
+ log.debug("serviceLocation=<" + serviceLocation + ">");
+ String xmlrpcURI = "http://" + hostPort + serviceLocation;
+
+ try {
+ client = new XmlRpcClient(xmlrpcURI);
+
+ /* Just check the collection does actually exist */
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ String exists = (String)
runRemoteCommand("GetCollectionConfiguration", params);
+ if (!"yes".equals(exists)) {
+
+ throw new XMLDBException(ErrorCodes.NO_SUCH_COLLECTION,
"Collection not found: " + collPath);
+ }
+ } catch (MalformedURLException e) {
+ client = null;
+ throw new XMLDBException(ErrorCodes.INVALID_URI, e);
+ } catch (XMLDBException x) {
+
+ throw x; // propagate any xmldb exception.
+ } catch (Exception e) {
+ client = null;
+ throw new XMLDBException(ErrorCodes.NO_SUCH_COLLECTION,
"Collection not found: " + collPath, e);
+ }
+ }
+
+ /**
+ * Submits a command for RPC to database server
+ *
+ * @param cmdName command name
+ * @param params hashtable containing named parameters to send to server
+ * @return the return value from the server. Type of return value
depends on
+ * command.
+ *
+ * @exception Exception thrown if XML-RPC reports an exception.
+ */
+ private Object runRemoteCommand(String cmdName, Hashtable params) throws
Exception {
+
+ params.put(RPCMessageInterface.MESSAGE_PARAM, cmdName);
+
+ Vector v = new Vector();
+ v.add(params);
+ return ((Hashtable) client.execute("run",
v)).get(RPCDefaultMessage.RESULT);
+ }
+
+ /**
+ * Retrieves a <code>Resource</code> from the database. If the
+ * <code>Resource</code> could not be
+ * located a null value will be returned.
+ *
+ * @param id the unique id for the requested resource.
+ * @return The retrieved <code>Resource</code> instance.
+ * @exception XMLDBException with expected error codes.<br />
+ * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
+ * specific errors that occur.<br />
+ * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
+ * method has been called on the <code>Collection</code><br />
+ */
+ public Resource getResource(String id) throws XMLDBException {
+
+ checkOpen();
+ try {
+
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ params.put(RPCDefaultMessage.NAME, id);
+ params.put(RPCDefaultMessage.COMPRESSED, "true");
+
+ Object result = runRemoteCommand("GetDocument", params);
+ /*
+ * If we get a Hashtable back then the result is compressed.
+ */
+ if (result instanceof Hashtable) {
+ Hashtable compressed = (Hashtable) result;
+ SymbolDeserializer symbolDeserial = new SymbolDeserializer();
+ return new XMLResourceImpl(id, id, this,
symbolDeserial.getSymbols(compressed), (byte[]) compressed.get("document"));
+ } else {
+ return new XMLResourceImpl(id, (String) result, this);
+ }
+
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the number of resources currently stored in this collection
or 0
+ * if the collection is empty.
+ *
+ * @return the number of resource in the collection.
+ * @exception XMLDBException with expected error codes.<br />
+ * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
+ * specific errors that occur.<br />
+ * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
+ * method has been called on the <code>Collection</code><br />
+ */
+ public int getResourceCount() throws XMLDBException {
+
+ checkOpen();
+ try {
+
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ return ((Integer) runRemoteCommand("GetDocumentCount",
params)).intValue();
+ } catch (XMLDBException x) {
+
+ throw x; // propagate any xmldb exception.
+ } catch (Exception e) {
+
+ throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e);
+ }
+ }
+
+ /**
+ * Stores the provided resource into the database. If the resource does
not
+ * already exist it will be created. If it does already exist it will be
+ * updated.
+ *
+ * @param res the resource to store in the database.
+ * @exception XMLDBException with expected error codes.<br />
+ * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
+ * specific errors that occur.<br />
+ * <code>ErrorCodes.INVALID_RESOURCE</code> if the
<code>Resource</code> is
+ * not valid.
+ * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
+ * method has been called on the <code>Collection</code><br />
+ */
+ public void storeResource(Resource res) throws XMLDBException {
+
+ if (!(res instanceof XMLResource)) {
+
+ throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, "Only XML
resources supported");
+ }
+
+ if (res.getContent() == null) {
+
+ throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, "no
resource data");
+ }
+ checkOpen();
+ try {
+
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ params.put(RPCDefaultMessage.NAME, res.getId());
+ params.put(RPCDefaultMessage.DOCUMENT, res.getContent());
+
+ String name = (String) runRemoteCommand("InsertDocument",
params);
+ ((XMLResourceImpl) res).setId(name);
+
+ } catch (XMLDBException x) {
+
+ throw x; // propagate any xmldb exception.
+ } catch (Exception e) {
+
+ throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e);
+ }
+ }
+
+ /* see superclass for documentation */
+ public boolean isOpen() {
+
+ return (client != null);
+ }
+
+ /* see superclass for documentation */
+ public String getURI() {
+
+ return "xmldb:" + DatabaseImpl.DRIVER_NAME + "://" + hostPort +
collPath;
+ }
+
+ /**
+ * Returns a <code>Collection</code> instance for the requested child
collection
+ * if it exists.
+ *
+ * @param name the name of the child collection to retrieve.
+ * @return the requested child collection or null if it couldn't be
found.
+ * @exception XMLDBException with expected error codes.<br />
+ * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
+ * specific errors that occur.<br />
+ * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
+ * method has been called on the <code>Collection</code><br />
+ */
+ public Collection getChildCollection(String name) throws XMLDBException {
+
+ if (name.indexOf('/') != -1) {
+
+ throw new XMLDBException(ErrorCodes.INVALID_COLLECTION);
+ }
+
+ try {
+ return new CollectionImpl(hostPort, serviceLocation,
xmlrpcDriver, collPath + "/" + name);
+ } catch (XMLDBException e) {
+
+ if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) {
+ // per getChildCollection contract, return null if not found
+ return null;
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Creates a new unique ID within the context of the
<code>Collection</code>
+ *
+ * @return the created id as a string.
+ * @exception XMLDBException with expected error codes.<br />
+ * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
+ * specific errors that occur.<br />
+ * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
+ * method has been called on the <code>Collection</code><br />
+ */
+ public String createId() throws XMLDBException {
+
+ checkOpen();
+ try {
+
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ return (String) runRemoteCommand("CreateNewOID", params);
+ } catch (XMLDBException x) {
+
+ throw x; // propagate any xmldb exception.
+ } catch (Exception e) {
+
+ throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e);
+ }
+ }
+
+ /**
+ * Releases all resources consumed by the <code>Collection</code>.
+ * The <code>close</code> method must
+ * always be called when use of a <code>Collection</code> is complete.
It is
+ * not safe to use a <code>Collection</code> after the
<code>close</code>
+ * method has been called.
+ *
+ * @exception XMLDBException with expected error codes.<br />
+ * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
+ * specific errors that occur.<br />
+ */
+ public void close() throws org.xmldb.api.base.XMLDBException {
+
+ client = null;
+ }
+
+ /**
+ * Returns the parent collection for this collection or null if no parent
+ * collection exists.
+ *
+ * @return the parent <code>Collection</code> instance.
+ * @exception XMLDBException with expected error codes.<br />
+ * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
+ * specific errors that occur.<br />
+ * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
+ * method has been called on the <code>Collection</code><br />
+ */
+ public Collection getParentCollection() throws XMLDBException {
+
+ // If there's only one slash then it's the root.
+ if (collPath.lastIndexOf("/") == 0) {
+ return null;
+ }
+
+ try {
+ return new CollectionImpl(hostPort, serviceLocation,
xmlrpcDriver, collPath.substring(0, collPath.lastIndexOf('/')));
+ } catch (XMLDBException e) {
+ if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) {
+ // per getParentCollection contract, return null if no parent
+ return null;
+ }
+ throw e;
+ }
+ }
+
+ /**
+ * Removes the <code>Resource</code> from the database.
+ *
+ * @param res the resource to remove.
+ * @exception XMLDBException with expected error codes.<br />
+ * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
+ * specific errors that occur.<br />
+ * <code>ErrorCodes.INVALID_RESOURCE</code> if the
<code>Resource</code> is
+ * not valid.<br />
+ * <code>ErrorCodes.NO_SUCH_RESOURCE</code> if the
<code>Resource</code> is
+ * not known to this <code>Collection</code>.
+ * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
+ * method has been called on the <code>Collection</code><br />
+ */
+ public void removeResource(Resource res) throws XMLDBException {
+
+ if (!(res instanceof XMLResource)) {
+
+ throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, "Only XML
resources supported");
+ }
+
+ if (res.getId() == null) {
+ throw new XMLDBException(ErrorCodes.VENDOR_ERROR, "This resource
is a query result and can " + "not be removed from the database.");
+ }
+
+ checkOpen();
+ try {
+
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ params.put(RPCDefaultMessage.NAME, res.getId());
+ runRemoteCommand("RemoveDocument", params);
+ } catch (XMLDBException x) {
+
+ throw x; // propagate any xmldb exception.
+ } catch (Exception e) {
+ throw new XMLDBException(ErrorCodes.NO_SUCH_RESOURCE, e);
+ }
+ }
+
+ /**
+ * Returns a list of collection names naming all child collections
+ * of the current collection. If no child collections exist an empty
list is
+ * returned.
+ *
+ * @return an array containing collection names for all child
+ * collections.
+ * @exception XMLDBException with expected error codes.<br />
+ * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
+ * specific errors that occur.<br />
+ * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
+ * method has been called on the <code>Collection</code><br />
+ */
+ public String[] listChildCollections() throws XMLDBException {
+
+ checkOpen();
+ try {
+
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ Vector list = (Vector) runRemoteCommand("ListCollections",
params);
+
+ return (String[]) list.toArray(new String[list.size()]);
+ } catch (XMLDBException x) {
+
+ throw x; // propagate any xmldb exception.
+ } catch (Exception e) {
+
+ throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e);
+ }
+ }
+
+ /**
+ * Returns the number of child collections under this
+ * <code>Collection</code> or 0 if no child collections exist.
+ *
+ * @return the number of child collections.
+ * @exception XMLDBException with expected error codes.<br />
+ * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
+ * specific errors that occur.<br />
+ * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
+ * method has been called on the <code>Collection</code><br />
+ */
+ public int getChildCollectionCount() throws XMLDBException {
+
+ checkOpen();
+ try {
+
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ Integer result = (Integer)
runRemoteCommand("GetCollectionCount", params);
+ return result.intValue();
+
+ } catch (XMLDBException x) {
+
+ throw x; // propagate any xmldb exception.
+ } catch (Exception e) {
+ throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e);
+ }
+ }
+
+ /**
+ * Returns a list of the ids for all resources stored in the collection.
+ *
+ * @return a string array containing the names for all
+ * <code>Resource</code>s in the collection.
+ * @exception XMLDBException with expected error codes.<br />
+ * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
+ * specific errors that occur.<br />
+ * <code>ErrorCodes.COLLECTION_CLOSED</code> if the <code>close</code>
+ * method has been called on the <code>Collection</code><br />
+ */
+ public String[] listResources() throws XMLDBException {
+
+ checkOpen();
+ try {
+
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ Vector list = (Vector) runRemoteCommand("ListDocuments", params);
+
+ return (String[]) list.toArray(new String[list.size()]);
+ } catch (XMLDBException x) {
+
+ throw x; // propagate any xmldb exception.
+ } catch (Exception e) {
+
+ throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e);
+ }
+ }
+
+ /* see superclass for documentation */
+ public ResourceSet query(String name, String queryLang, String query,
Hashtable nsMap) throws XMLDBException {
+
+ checkOpen();
+ try {
+
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ params.put(RPCDefaultMessage.TYPE, queryLang);
+ params.put(RPCDefaultMessage.NAMESPACES, nsMap);
+ params.put(RPCDefaultMessage.QUERY, query);
+
+ if (name != null) {
+
+ params.put(RPCDefaultMessage.NAME, name);
+ }
+
+ String result = (String) runRemoteCommand("Query", params);
+ DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ Document resultDoc = dbf.newDocumentBuilder().parse(new
InputSource(new StringReader(result)));
+
+ ResourceSetImpl rs = new ResourceSetImpl(this, resultDoc);
+
+ return rs;
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw
FaultCodes.createXMLDBException(FaultCodes.QRY_PROCESSING_ERROR, "Query error",
e);
+ }
+ }
+
+ /* see superclass for documentation */
+ public Collection createCollection(String name) throws XMLDBException {
+ return createCollection(name, null);
+ }
+
+ /* see superclass for documentation */
+ public Collection createCollection(String name, Document configuration)
throws XMLDBException {
+ checkOpen();
+ try {
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ params.put(RPCDefaultMessage.NAME, name);
+ if (configuration != null) {
+ params.put(RPCDefaultMessage.CONFIGURATION,
TextWriter.toString(configuration));
+ }
+
+ runRemoteCommand("CreateCollection", params);
+
+ return getChildCollection(name);
+ } catch (XMLDBException x) {
+
+ throw x; // propagate any xmldb exception.
+ } catch (Exception e) {
+ throw new XMLDBException(ErrorCodes.INVALID_COLLECTION, "Cannot
create child collection", e);
+ }
+ }
+
+ /* see superclass for documentation */
+ public void removeCollection(String childName) throws XMLDBException {
+
+// todo: shortcut the call and fail immediatly if the collection name is
null or empty
+
+ checkOpen();
+ try {
+
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ params.put(RPCDefaultMessage.NAME, childName);
+ String result = (String) runRemoteCommand("RemoveCollection",
params);
+
+ if (!result.equals("yes")) {
+
+ throw new XMLDBException(ErrorCodes.INVALID_COLLECTION,
"Cannot remove child collection[" + childName + "]");
+ }
+ } catch (XMLDBException x) {
+
+ throw x; // propagate any xmldb exception.
+ } catch (Exception e) {
+
+ throw new XMLDBException(ErrorCodes.INVALID_COLLECTION, "Cannot
remove child collection[" + childName + "]", e);
+ }
+ }
+
+ /* see superclass for documentation */
+ public String[] listIndexers() throws XMLDBException {
+ checkOpen();
+ try {
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ Vector list = (Vector) runRemoteCommand("ListIndexers", params);
+
+ return (String[]) list.toArray(new String[list.size()]);
+ } catch (Exception e) {
+ throw FaultCodes.createXMLDBException(e);
+ }
+ }
+
+ /* see superclass for documentation */
+ public void createIndexer(Document configuration) throws XMLDBException {
+ checkOpen();
+ try {
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ params.put(RPCDefaultMessage.CONFIGURATION,
TextWriter.toString(configuration));
+
+ runRemoteCommand("CreateIndexer", params);
+ } catch (Exception e) {
+ throw FaultCodes.createXMLDBException(e);
+ }
+ }
+
+ /* see superclass for documentation */
+ public void dropIndexer(String name) throws XMLDBException {
+ checkOpen();
+ try {
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ params.put(RPCDefaultMessage.NAME, name);
+
+ runRemoteCommand("RemoveIndexer", params);
+ } catch (Exception e) {
+ throw FaultCodes.createXMLDBException(e);
+ }
+ }
+
+ /* see superclass for documentation */
+ public void shutdown() throws XMLDBException {
+ checkOpen();
+ try {
+ Hashtable params = new Hashtable();
+
+ runRemoteCommand("Shutdown", params);
+ } catch (Exception e) {
+ throw FaultCodes.createXMLDBException(e);
+ }
+ }
+
+ public MetaData getMetaData(String id) throws XMLDBException {
+ checkOpen();
+ try {
+ Hashtable params = new Hashtable();
+ params.put(RPCDefaultMessage.COLLECTION, collPath);
+ if (id != null) {
+ params.put(RPCDefaultMessage.NAME, id);
+ }
+ params.put(RPCDefaultMessage.COMPRESSED, "true");
+
+ Object result = runRemoteCommand(id == null ?
"GetCollectionMeta" : "GetDocumentMeta", params);
+ Document metaDoc = DOMParser.toDocument(result.toString());
+ MetaData meta = new MetaData(id);
+ meta.streamFromXML(metaDoc.getDocumentElement(), true);
+ return meta;
+ } catch (Exception e) {
+ throw FaultCodes.createXMLDBException(e);
+ }
+ }
}