Package org.apache.xindice.client.xmldb.xmlrpc

Source Code of org.apache.xindice.client.xmldb.xmlrpc.DatabaseImpl

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* $Id: DatabaseImpl.java 511426 2007-02-25 03:25:02Z vgritsenko $
*/

package org.apache.xindice.client.xmldb.xmlrpc;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xindice.client.xmldb.CommonConfigurable;
import org.apache.xmlrpc.XmlRpc;
import org.apache.xmlrpc.XmlRpcClient;

import org.xmldb.api.base.Collection;
import org.xmldb.api.base.Database;
import org.xmldb.api.base.ErrorCodes;
import org.xmldb.api.base.XMLDBException;

import java.net.MalformedURLException;

/**
* Implements XML:DB's <code>Database</code> interface using XML-RPC to communicate
* with the Xindice XML-RPC server. Usually, this class is not used
* directly, but {@link org.apache.xindice.client.xmldb.DatabaseImpl} is used instead.
*
* Note this class is a database <em>driver</em>, and one class of this database
* could be used to connect to <em>many</em> different databases, on one or
* different Xindice XML-RPC servers.
*
* XML-RPC database driver uses following configuration parameters:
* <ul>
* <li><strong>service-location</strong>: Specifies path to the Xindice server WebApp</li>
* <li><strong>xmlrpc-driver</strong>: Specifies name of the SAX parser to use</li>
* <li><strong>xmlrpc-user</strong>: If server protected with HTTP Basic Auth, specifies user name</li>
* <li><strong>xmlrpc-password</strong>: If server protected with HTTP Basic Auth, specifies password</li>
* </ul>
*
* If one of these parameters is not specified, system properties will be used.
*
* @author <a href="mailto:james.bates@amplexor.com">James Bates</a>
* @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
* @version $Revision: 511426 $, $Date: 2007-02-24 22:25:02 -0500 (Sat, 24 Feb 2007) $
*/
public class DatabaseImpl extends CommonConfigurable implements Database {

    private static final Log log = LogFactory.getLog(DatabaseImpl.class);

    /**
     * Driver property name for the xml-rpc service location.
     */
    public static final String PROP_SERVICE_LOCATION = "service-location";

    /**
     * System property name for the service location
     */
    public static final String SYSPROP_SERVICE_LOCATION = "xindice.xmlrpc.service-location";

    /**
     * Driver property name for the SAX parser xml-rpc will use.
     */
    public static final String PROP_XMLRPC_DRIVER = "xmlrpc-driver";

    /**
     * System property name for the SAX parser xml-rpc will use in case
     * there were no configuration property passed
     */
    public static final String SYSPROP_XMLRPC_DRIVER = "xindice.xmlrpc.driver";

    /**
     * Driver property name for the basic authentication user name.
     */
    public static final String PROP_XMLRPC_USER = "xmlrpc-user";

    /**
     * System property name for the basic authentication user name in case
     * there were no configuration property passed
     */
    public static final String SYSPROP_XMLRPC_USER = "xindice.xmlrpc.user";

    /**
     * Driver property name for the basic authentication password.
     */
    public static final String PROP_XMLRPC_PASSWORD = "xmlrpc-password";

    /**
     * System property name for the basic authentication password in case
     * there were no configuration property passed
     */
    public static final String SYSPROP_XMLRPC_PASSWORD = "xindice.xmlrpc.password";

    /**
     * Default value of the xmlrpc-driver property
     */
    private static final String DEFAULT_XMLRPC_DRIVER = "xerces";

    /**
     * Default path to the XML-RPC service in the web server
     */
    private static final String DEFAULT_SERVICE_LOCATION = "/xindice/";

    /**
     * Prefix used to denote XML:DB URI's that should use this driver
     */
    public static final String DRIVER_NAME = "xindice";

    /**
     * XML:DB conformance level of this driver
     */
    private static final String CONFORMANCE_LEVEL = "0";

    /**
     * Ensures that XML-RPC static properties initialized just once
     */
    private static boolean xmlRpcInitialized;

    /**
     * Location of the XML-RPC service in the web server
     */
    private String serviceLocation;

    private String basicUser;
    private String basicPassword;


    /**
     * Create a new DatabaseImpl object.
     */
    public DatabaseImpl() {
        super();
    }

    /**
     * Create a new DatabaseImpl object with a copy of the properties
     * from the DatabaseImpl parameter.
     *
     * @param config from which the initial parameters for this
     *        DatabaseImpl object are copied.
     */
    public DatabaseImpl(CommonConfigurable config) {
        super(config);
    }

    /**
     * Determines whether this <code>Database</code> implementation  can handle
     * the URI. It should return true if the Database instance knows how to
     * handle the URI and false otherwise.
     *
     * @param uri the URI to check for.
     * @return true if the URI can be handled, false otherwise.
     * @exception XMLDBException with expected error codes.<br />
     <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
     *  specific errors that occur.<br />
     <code>ErrroCodes.INVALID_URI</code> If the URI is not in a valid format. <br />
     */
    public boolean acceptsURI(String uri) throws XMLDBException {

        return ((uri != null) && uri.startsWith(getName() + "://"));
    }

    /**
     * Initialize XML-RPC library static properties: encoding, keep-alive, SAX driver.
     *
     * @throws XMLDBException if specified (or default, if none specified) SAX driver
     *         class could not be loaded
     */
    private void initialize() throws XMLDBException {
        synchronized (getClass()) {
            if (!xmlRpcInitialized) {
                XmlRpc.setEncoding("UTF8");
                XmlRpc.setKeepAlive(true);

                /*
                 * Determine the SAXparser the xmlrpc client will use.
                 *
                 * In priority order:
                 *   DatabaseImpl xmlrpc-driver property
                 *      (passed in the xmlrpc-driver parameter)
                 *   System property "xindice.xmlrpc.driver"
                 *   Default value "xerces"
                 */
                String xmlrpcDriver = getProperty(PROP_XMLRPC_DRIVER);
                if (xmlrpcDriver == null) {
                    xmlrpcDriver = System.getProperty(SYSPROP_XMLRPC_DRIVER);
                    if (xmlrpcDriver == null) {
                        xmlrpcDriver = DEFAULT_XMLRPC_DRIVER;
                    }
                }

                try {
                    if (log.isDebugEnabled()) {
                        log.debug("Using SAX Driver: '" + xmlrpcDriver + "'");
                    }
                    XmlRpc.setDriver(xmlrpcDriver);
                } catch (Exception e) {
                    throw new XMLDBException(ErrorCodes.VENDOR_ERROR,
                                             "SAX Driver " + xmlrpcDriver + " is not available", e);
                }
            }

            xmlRpcInitialized = true;
        }
    }

    /**
     * Initialize XML-RPC service location, basic authentication.
     * Create XML-RPC client.
     *
     * @param hostPort of the Xindice XML-RPC server
     * @return XML-RPC client connected to the Xindice server
     * @throws XMLDBException
     */
    private XmlRpcClient connect(String hostPort) throws XMLDBException {

        // Initialize XML-RPC static properties
        initialize();

        synchronized (this) {
            if (serviceLocation == null) {

                /*
                 * 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/"
                 */
                serviceLocation = getProperty(PROP_SERVICE_LOCATION);
                if (serviceLocation == null) {
                    serviceLocation = System.getProperty(SYSPROP_SERVICE_LOCATION);
                    if (serviceLocation == null) {
                        serviceLocation = DEFAULT_SERVICE_LOCATION;
                    }
                }

                if (!serviceLocation.startsWith("/")) {
                    serviceLocation = "/" + serviceLocation;
                }
                if (!serviceLocation.endsWith("/")) {
                    serviceLocation = serviceLocation + "/";
                }

                if (log.isDebugEnabled()) {
                    log.debug("Using Service Location: '" + serviceLocation + "'");
                }

                /*
                 * Determine basic authentication parameters
                 */
                basicUser = getProperty(PROP_XMLRPC_USER);
                if (basicUser == null) {
                    basicUser = System.getProperty(SYSPROP_XMLRPC_USER);
                }

                if (basicUser != null) {
                    basicPassword = getProperty(PROP_XMLRPC_PASSWORD);
                    if (basicPassword == null) {
                        basicPassword = System.getProperty(SYSPROP_XMLRPC_PASSWORD);
                    }
                    if (log.isDebugEnabled()) {
                        log.debug("Using Basic authentication. User: '" + basicUser + "', password: '" + basicPassword + "'");
                    }
                }
            }
        }


        String xmlRpcURL = "http://" + hostPort + serviceLocation;
        try {
            if (log.isDebugEnabled()) {
                log.debug("Using URI: '" + xmlRpcURL + "'");
            }
            XmlRpcClient client = new XmlRpcClient(xmlRpcURL);
            if (basicUser != null) {
                client.setBasicAuthentication(basicUser, basicPassword);
            }
            return client;
        } catch (MalformedURLException e) {
            throw new XMLDBException(ErrorCodes.INVALID_URI, e);
        }
    }

    /**
     * Retrieves a <code>Collection</code> instance based on the URI provided
     * in the <code>uri</code> parameter. The format of the URI is defined in the
     * documentation for DatabaseManager.getCollection().<p/>
     *
     * Authentication is handled via username and password however it is not
     * required that the database support authentication. Databases that do not
     * support authentication MUST ignore the
     * <code>username</code> and <code>password</code> if those provided are not
     * null.
     *
     * @param uri the URI to use to locate the collection.
     * @param password The password to use for authentication to the database or
     *    null if the database does not support authentication.
     * @return A <code>Collection</code> instance for the requested collection or
     *  null if the collection could not be found.
     * @return The <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>ErrroCodes.INVALID_URI</code> If the URI is not in a valid format. <br />
     <code>ErrroCodes.PERMISSION_DENIED</code> If the <code>username</code>
     *    and <code>password</code> were not accepted by the database.
     */
    public Collection getCollection(String uri, String userName, String password) throws XMLDBException {
        /* TODO: introduce authentication some day */

        if (!acceptsURI(uri)) {
            throw new XMLDBException(ErrorCodes.INVALID_URI,
                                     "Invalid URL: " + uri);
        }

        /* Chop off driver prefix, and '://' */
        uri = uri.substring(getName().length() + 3);

        /* Extract host name & port, if present */
        int firstSlash = uri.indexOf('/');
        if (firstSlash == -1) {
            throw new XMLDBException(ErrorCodes.INVALID_URI,
                                     "Invalid URL (must have '/'): " + uri);
        }

        /* Extract collection name */
        String collPath = uri.substring(firstSlash);
        if (!collPath.startsWith("/")) {
            throw new XMLDBException(ErrorCodes.INVALID_URI,
                                     "Invalid URL (collection name must start with '/'): " + uri);
        }

        String hostPort = uri.substring(0, firstSlash);

        /* Absent host defaults to localhost and standard Xindice HTTP port */
        if (hostPort.equals("")) {
            hostPort = "127.0.0.1:8888";
        }

        try {
            return new CollectionImpl(connect(hostPort), collPath);
        } catch (XMLDBException e) {
            if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) {
                // per getCollection contract, return null if not found
                return null;
            }
            throw e;
        }
    }

    /**
     * Returns the prefix used in XML:DB to denote URI's that this driver can
     * handle.
     *
     * @return the prefix driver name
     * @exception XMLDBException with expected error codes.<br />
     <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
     *  specific errors that occur.<br />
     */
    public String getName() throws XMLDBException {
        return DRIVER_NAME;
    }

    /**
     * Returns an array of names associated with the Database instance.
     *
     * @return the array of name of the object.
     * @exception XMLDBException with expected error codes.<br />
     <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
     *  specific errors that occur.<br />
     */
    public String[] getNames() throws XMLDBException {
        return new String[]{ getName() };
    }

    /**
     * Returns the XML:DB API Conformance level for the implementation. This can
     * be used by client programs to determine what functionality is available to
     * them.
     *
     * @return the XML:DB API conformance level for this implementation.
     * @exception XMLDBException with expected error codes.<br />
     <code>ErrorCodes.VENDOR_ERROR</code> for any vendor
     *  specific errors that occur.<br />
     */
    public String getConformanceLevel() throws XMLDBException {
        return CONFORMANCE_LEVEL;
    }
}
TOP

Related Classes of org.apache.xindice.client.xmldb.xmlrpc.DatabaseImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.