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); + } + } }