/* * eXist Open Source Native XML Database * Copyright (C) 2003-2007 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id$ */ package org.exist.xmldb; import org.apache.xmlrpc.XmlRpcException; import org.exist.source.Source; import org.exist.xmlrpc.RpcAPI; import org.exist.xquery.XPathException; import org.xmldb.api.base.Collection; import org.xmldb.api.base.CompiledExpression; import org.xmldb.api.base.ErrorCodes; import org.xmldb.api.base.Resource; import org.xmldb.api.base.ResourceSet; import org.xmldb.api.base.XMLDBException; import org.xmldb.api.modules.XMLResource; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Properties; public class RemoteXPathQueryService implements XPathQueryServiceImpl, XQueryService { protected RemoteCollection collection; protected HashMap namespaceMappings = new HashMap(5); protected HashMap variableDecls = new HashMap(); protected Properties outputProperties = null; protected boolean protectedMode = false; /** * Creates a new <code>RemoteXPathQueryService</code> instance. * * @param collection a <code>RemoteCollection</code> value */ public RemoteXPathQueryService(RemoteCollection collection) { this.collection = collection; this.outputProperties = new Properties(collection.properties); } /** * The method <code>query</code> * * @param query a <code>String</code> value * @return a <code>ResourceSet</code> value * @exception XMLDBException if an error occurs */ public ResourceSet query(String query) throws XMLDBException { return query(query, null); } /** * The method <code>query</code> * * @param query a <code>String</code> value * @param sortExpr a <code>String</code> value * @return a <code>ResourceSet</code> value * @exception XMLDBException if an error occurs */ public ResourceSet query(String query, String sortExpr) throws XMLDBException { try { HashMap optParams = new HashMap(); if(sortExpr != null) optParams.put(RpcAPI.SORT_EXPR, sortExpr); if(namespaceMappings.size() > 0) optParams.put(RpcAPI.NAMESPACES, namespaceMappings); if(variableDecls.size() > 0) optParams.put(RpcAPI.VARIABLES, variableDecls); optParams.put(RpcAPI.BASE_URI, outputProperties.getProperty("base-uri", collection.getPath())); if (protectedMode) optParams.put(RpcAPI.PROTECTED_MODE, collection.getPath()); List params = new ArrayList(2); params.add(query.getBytes("UTF-8")); params.add(optParams); HashMap result = (HashMap) collection.getClient().execute("queryP", params); if(result.get(RpcAPI.ERROR) != null) throwException(result); Object[] resources = (Object[]) result.get("results"); int handle = -1; int hash = -1; if(resources != null && resources.length > 0) { handle = ((Integer)result.get("id")).intValue(); Integer hashValue = (Integer)result.get("hash"); hash = hashValue == null ? -1 : hashValue.intValue(); } return new RemoteResourceSet( collection, outputProperties, resources, handle, hash ); } catch ( XmlRpcException xre ) { throw new XMLDBException( ErrorCodes.VENDOR_ERROR, xre.getMessage(), xre ); } catch ( IOException ioe ) { throw new XMLDBException( ErrorCodes.VENDOR_ERROR, ioe.getMessage(), ioe ); } } /** * The method <code>compile</code> * * @param query a <code>String</code> value * @return a <code>CompiledExpression</code> value * @exception XMLDBException if an error occurs */ public CompiledExpression compile(String query) throws XMLDBException { try { return compileAndCheck(query); } catch (XPathException e) { throw new XMLDBException( ErrorCodes.VENDOR_ERROR, e.getMessage(), e ); } } /** * The method <code>compileAndCheck</code> * * @param query a <code>String</code> value * @return a <code>CompiledExpression</code> value * @exception XMLDBException if an error occurs * @exception XPathException if an error occurs */ public CompiledExpression compileAndCheck(String query) throws XMLDBException, XPathException { try { HashMap optParams = new HashMap(); if(namespaceMappings.size() > 0) optParams.put(RpcAPI.NAMESPACES, namespaceMappings); if(variableDecls.size() > 0) optParams.put(RpcAPI.VARIABLES, variableDecls); optParams.put(RpcAPI.BASE_URI, outputProperties.getProperty("base-uri", collection.getPath())); List params = new ArrayList(2); params.add(query.getBytes("UTF-8")); params.add(optParams); HashMap result = (HashMap) collection.getClient().execute( "compile", params ); if (result.get(RpcAPI.ERROR) != null) throwXPathException(result); return new RemoteCompiledExpression(query); } catch ( XmlRpcException xre ) { throw new XMLDBException( ErrorCodes.VENDOR_ERROR, xre.getMessage(), xre ); } catch ( IOException ioe ) { throw new XMLDBException( ErrorCodes.VENDOR_ERROR, ioe.getMessage(), ioe ); } } /** * The method <code>throwException</code> * * @param result * @exception XMLDBException if an error occurs */ private void throwException(HashMap result) throws XMLDBException { String message = (String)result.get(RpcAPI.ERROR); Integer lineInt = (Integer)result.get(RpcAPI.LINE); Integer columnInt = (Integer)result.get(RpcAPI.COLUMN); int line = lineInt == null ? 0 : lineInt.intValue(); int column = columnInt == null ? 0 : columnInt.intValue(); XPathException cause = new XPathException(line, column, message); throw new XMLDBException(ErrorCodes.VENDOR_ERROR, message, cause); } /** * The method <code>throwXPathException</code> * * @param result a <code>Hashtable</code> value * @exception XPathException if an error occurs */ private void throwXPathException(HashMap result) throws XPathException { String message = (String)result.get(RpcAPI.ERROR); Integer lineInt = (Integer)result.get(RpcAPI.LINE); Integer columnInt = (Integer)result.get(RpcAPI.COLUMN); int line = lineInt == null ? 0 : lineInt.intValue(); int column = columnInt == null ? 0 : columnInt.intValue(); throw new XPathException(line, column, message); } /* (non-Javadoc) * @see org.exist.xmldb.XQueryService#execute(org.exist.source.Source) */ public ResourceSet execute(Source source) throws XMLDBException { try { String xq = source.getContent(); return query(xq, null); } catch (IOException e) { throw new XMLDBException( ErrorCodes.VENDOR_ERROR, e.getMessage(), e ); } } /** * The method <code>query</code> * * @param res a <code>XMLResource</code> value * @param query a <code>String</code> value * @return a <code>ResourceSet</code> value * @exception XMLDBException if an error occurs */ public ResourceSet query(XMLResource res, String query) throws XMLDBException { return query(res, query, null); } /** * The method <code>query</code> * * @param res a <code>XMLResource</code> value * @param query a <code>String</code> value * @param sortExpr a <code>String</code> value * @return a <code>ResourceSet</code> value * @exception XMLDBException if an error occurs */ public ResourceSet query(XMLResource res, String query, String sortExpr) throws XMLDBException { RemoteXMLResource resource = (RemoteXMLResource) res; try { HashMap optParams = new HashMap(); if(namespaceMappings.size() > 0) optParams.put(RpcAPI.NAMESPACES, namespaceMappings); if(variableDecls.size() > 0) optParams.put(RpcAPI.VARIABLES, variableDecls); if(sortExpr != null) optParams.put(RpcAPI.SORT_EXPR, sortExpr); optParams.put(RpcAPI.BASE_URI, outputProperties.getProperty("base-uri", collection.getPath())); if (protectedMode) optParams.put(RpcAPI.PROTECTED_MODE, collection.getPath()); List params = new ArrayList(5); params.add(query.getBytes("UTF-8")); params.add(resource.path.toString()); if(resource.id == null) params.add(""); else params.add(resource.id); params.add(optParams); HashMap result = (HashMap) collection.getClient().execute("queryP", params); if(result.get(RpcAPI.ERROR) != null) throwException(result); Object[] resources = (Object[]) result.get("results"); int handle = -1; int hash = -1; if(resources != null && resources.length > 0) { handle = ((Integer) result.get("id")).intValue(); hash = ((Integer)result.get("hash")).intValue(); } return new RemoteResourceSet(collection, outputProperties, resources, handle, hash); } catch (XmlRpcException xre) { throw new XMLDBException(ErrorCodes.VENDOR_ERROR, xre.getMessage(), xre); } catch (IOException ioe) { throw new XMLDBException(ErrorCodes.VENDOR_ERROR, ioe.getMessage(), ioe); } } /** * The method <code>queryResource</code> * * @param resource a <code>String</code> value * @param query a <code>String</code> value * @return a <code>ResourceSet</code> value * @exception XMLDBException if an error occurs */ public ResourceSet queryResource(String resource, String query) throws XMLDBException { Resource res = collection.getResource(resource); if(res == null) throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, "Resource " + resource + " not found"); if(!"XMLResource".equals(res.getResourceType())) throw new XMLDBException(ErrorCodes.INVALID_RESOURCE, "Resource " + resource + " is not an XML resource"); return query((XMLResource) res, query); } /** * The method <code>getVersion</code> * * @return a <code>String</code> value * @exception XMLDBException if an error occurs */ public String getVersion() throws XMLDBException { return "1.0"; } /** * The method <code>setCollection</code> * * @param col a <code>Collection</code> value * @exception XMLDBException if an error occurs */ public void setCollection(Collection col) throws XMLDBException { } /** * The method <code>getName</code> * * @return a <code>String</code> value * @exception XMLDBException if an error occurs */ public String getName() throws XMLDBException { return "XPathQueryService"; } /** * The method <code>getProperty</code> * * @param property a <code>String</code> value * @return a <code>String</code> value * @exception XMLDBException if an error occurs */ public String getProperty(String property) throws XMLDBException { return outputProperties.getProperty(property); } /** * The method <code>setProperty</code> * * @param property a <code>String</code> value * @param value a <code>String</code> value * @exception XMLDBException if an error occurs */ public void setProperty(String property, String value) throws XMLDBException { outputProperties.setProperty(property, value); } /** * The method <code>clearNamespaces</code> * * @exception XMLDBException if an error occurs */ public void clearNamespaces() throws XMLDBException { namespaceMappings.clear(); } /** * The method <code>removeNamespace</code> * * @param ns a <code>String</code> value * @exception XMLDBException if an error occurs */ public void removeNamespace(final String ns) throws XMLDBException { for(Iterator i = namespaceMappings.values().iterator(); i.hasNext(); ) { if(i.next().equals(ns)) i.remove(); } } /** * The method <code>setNamespace</code> * * @param prefix a <code>String</code> value * @param namespace a <code>String</code> value * @exception XMLDBException if an error occurs */ public void setNamespace(String prefix, String namespace) throws XMLDBException { if (prefix == null) prefix = ""; namespaceMappings.put(prefix, namespace); } /** * The method <code>getNamespace</code> * * @param prefix a <code>String</code> value * @return a <code>String</code> value * @exception XMLDBException if an error occurs */ public String getNamespace(String prefix) throws XMLDBException { if (prefix == null) prefix = ""; return (String)namespaceMappings.get(prefix); } /* (non-Javadoc) * @see org.exist.xmldb.XPathQueryServiceImpl#declareVariable(java.lang.String, java.lang.Object) */ public void declareVariable(String qname, Object initialValue) throws XMLDBException { variableDecls.put(qname, initialValue); } /* (non-Javadoc) * @see org.exist.xmldb.XQueryService#execute(org.exist.xmldb.CompiledExpression) */ public ResourceSet execute(CompiledExpression expression) throws XMLDBException { return query(((RemoteCompiledExpression) expression).getQuery()); } /* (non-Javadoc) * @see org.exist.xmldb.XQueryService#execute(org.xmldb.api.modules.XMLResource, org.exist.xmldb.CompiledExpression) */ public ResourceSet execute(XMLResource res, CompiledExpression expression) throws XMLDBException { return query(res, ((RemoteCompiledExpression) expression).getQuery()); } /* (non-Javadoc) * @see org.exist.xmldb.XQueryService#setXPathCompatibility(boolean) */ public void setXPathCompatibility(boolean backwardsCompatible) { // TODO: not passed } /** * Calling this method has no effect. The server loads modules * relative to its own context. * * @see org.exist.xmldb.XQueryService#setModuleLoadPath(java.lang.String) */ public void setModuleLoadPath(String path) { } /* (non-Javadoc) * @see org.exist.xmldb.XQueryService#dump(org.exist.xmldb.CompiledExpression, java.io.Writer) */ public void dump(CompiledExpression expression, Writer writer) throws XMLDBException { String query = ((RemoteCompiledExpression)expression).getQuery(); HashMap optParams = new HashMap(); if(namespaceMappings.size() > 0) optParams.put(RpcAPI.NAMESPACES, namespaceMappings); if(variableDecls.size() > 0) optParams.put(RpcAPI.VARIABLES, variableDecls); optParams.put(RpcAPI.BASE_URI, outputProperties.getProperty("base-uri", collection.getPath())); List params = new ArrayList(2); params.add(query); params.add(optParams); try { String dump = (String)collection.getClient().execute("printDiagnostics", params); writer.write(dump); } catch (XmlRpcException e) { throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e.getMessage(), e); } catch (IOException e) { throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR, e.getMessage(), e); } } /* (non-Javadoc) * @see org.exist.xmldb.XPathQueryServiceImpl#beginProtected() */ public void beginProtected() { protectedMode = true; } /* (non-Javadoc) * @see org.exist.xmldb.XPathQueryServiceImpl#endProtected() */ public void endProtected() { protectedMode = false; } }