You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xindice-dev@xml.apache.org by vg...@apache.org on 2004/02/06 14:05:56 UTC

cvs commit: xml-xindice/java/src/org/apache/xindice/client/xmldb/embed DatabaseImpl.java

vgritsenko    2004/02/06 05:05:56

  Modified:    .        status.xml
               config   system.xml
               java/src/org/apache/xindice/client/xmldb/embed
                        DatabaseImpl.java
  Log:
  Support multiple databases (embed driver only)
  
  Revision  Changes    Path
  1.26      +6 -1      xml-xindice/status.xml
  
  Index: status.xml
  ===================================================================
  RCS file: /home/cvs/xml-xindice/status.xml,v
  retrieving revision 1.25
  retrieving revision 1.26
  diff -u -r1.25 -r1.26
  --- status.xml	2 Feb 2004 14:36:19 -0000	1.25
  +++ status.xml	6 Feb 2004 13:05:56 -0000	1.26
  @@ -59,7 +59,12 @@
       </todo>
   
       <changes>
  -        <release version="1.1b4-dev" date="February 2 2004">
  +        <release version="1.1b4-dev" date="February 6 2004">
  +            <action dev="VG" type="update">
  +                Embedded driver supports two configuration variables (see javadoc
  +                for details), and multiple database instances (see system.xml for an
  +                example).
  +            </action>
               <action dev="VG" type="update">
                   Add max-descriptors configuration attribute to all Filer implementations
                   based on Paged. Default value is 16 file descriptors (same as before).
  
  
  
  1.15      +19 -5     xml-xindice/config/system.xml
  
  Index: system.xml
  ===================================================================
  RCS file: /home/cvs/xml-xindice/config/system.xml,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- system.xml	30 Dec 2003 13:07:38 -0000	1.14
  +++ system.xml	6 Feb 2004 13:05:56 -0000	1.15
  @@ -9,12 +9,13 @@
   <xindice>
   
       <!--
  -      - Defines the database instance. This release supports only one
  -      - database instance. Attributes:
  +      - Defines the database instance. Xindice server in servlet mode currently
  +      - supports only one database instance. Attributes:
         -   dbroot:
  -      -       Identifies location of the database.
  +      -       Identifies location of the database. Relative paths will be
  +      -       resolved depending on mode of operation.
         -   name:
  -      -       Name of the database instance,
  +      -       Name of the database instance.
         -   use-metadata:
         -       When set to 'on', enables external metadata facilities
         -       for this database instance.
  @@ -30,6 +31,19 @@
           </filer>
           -->
   
  +        <!--
  +          - Query Engine Configuration.
  +          -->
  +        <queryengine>
  +            <resolver autoindex="false" class="org.apache.xindice.core.query.XPathQueryResolver"/>
  +            <resolver class="org.apache.xindice.core.xupdate.XUpdateQueryResolver"/>
  +        </queryengine>
  +    </root-collection>
  +
  +    <!--
  +      - Embedded driver suuports several DB instances.
  +      -->
  +    <root-collection dbroot="./db2/" name="db2" use-metadata="off">
           <queryengine>
               <resolver autoindex="false" class="org.apache.xindice.core.query.XPathQueryResolver"/>
               <resolver class="org.apache.xindice.core.xupdate.XUpdateQueryResolver"/>
  
  
  
  1.23      +169 -75   xml-xindice/java/src/org/apache/xindice/client/xmldb/embed/DatabaseImpl.java
  
  Index: DatabaseImpl.java
  ===================================================================
  RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/client/xmldb/embed/DatabaseImpl.java,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- DatabaseImpl.java	22 Jan 2004 03:23:37 -0000	1.22
  +++ DatabaseImpl.java	6 Feb 2004 13:05:56 -0000	1.23
  @@ -66,6 +66,8 @@
   import org.apache.xindice.server.Xindice;
   import org.apache.xindice.util.Configuration;
   import org.apache.xindice.util.XindiceException;
  +import org.apache.xindice.util.XindiceRuntimeException;
  +import org.apache.xindice.util.ReadOnlyException;
   import org.apache.xindice.xml.dom.DOMParser;
   
   import org.xmldb.api.base.Collection;
  @@ -75,14 +77,41 @@
   import java.io.File;
   import java.io.FileInputStream;
   import java.io.IOException;
  +import java.io.FileNotFoundException;
   
   /**
  - * implements XML:DB's <code>Database</code> interface providing
  - * embedded access to a Xindice database.
  + * Implements XML:DB's <code>Database</code> interface providing embedded access to
  + * a Xindice database. Usually, this class is not used
  + * directly, use {@link org.apache.xindice.client.xmldb.DatabaseImpl} instead.
  + *
  + * Embedded database driver supports multiple database instances simultaneously. To use
  + * multiple instances, use several instances of this driver with different values for
  + * the Xindice DB Name property.
  + *
  + * Embedded database driver uses following configuration parameters:
  + * <ul>
  + * <li>Xindice DB Home</li>
  + * <li>Xindice Configuration</li>
  + * </ul>
  + *
  + * These parameters can be specified either:
  + * <ul>
  + * <li>by instantiating {@link org.apache.xindice.client.xmldb.DatabaseImpl}
  + *     and setting its properties (see {@link #setProperty}). You don't need to use
  + *     this class directly in this case.</li>
  + * <li>by setting Java system properties (see {@link System#setProperty(String, String)})</li>
  + * <li>by using constructor {@link DatabaseImpl#DatabaseImpl(CommonConfigurable)} and
  + *     passing instance of CommonConfigurable with all properties already set.</li>
  + * <li>by using {@link #setProperty} <strong>before</strong> calling
  + *     {@link #getCollection(String, String, String)}.</li>
  + *
  + * These properties are used in the getCollection method, and changes in those properties will
  + * not affect this instance of the driver after collection is obtained.
    *
    * @author <a href="mailto:kstaken@xmldatabases.org">Kimbro Staken</a>
    * @author <a href="mailto:james.bates@amplexor.com">James Bates</a>
    * @author <a href="mailto:vladimir@apache.org">Vladimir R. Bossicard</a>
  + * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
    * @version CVS $Revision$, $Date$
    */
   public class DatabaseImpl extends CommonConfigurable implements org.xmldb.api.base.Database {
  @@ -90,6 +119,26 @@
       private static final Log log = LogFactory.getLog(DatabaseImpl.class);
   
       /**
  +     * Driver property name for the xindice database home.
  +     */
  +    private static final String PROP_XINDICE_DB_HOME = "db-home";
  +
  +    /**
  +     * System property name for the xindice database home.
  +     */
  +    private static final String SYSPROP_XINDICE_DB_HOME = Xindice.PROP_XINDICE_DB_HOME;
  +
  +    /**
  +     * Driver property name for the xindice configuration file.
  +     */
  +    private static final String PROP_XINDICE_CONFIGURATION = "configuration";
  +
  +    /**
  +     * Driver property name for the xindice configuration file.
  +     */
  +    private static final String SYSPROP_XINDICE_CONFIGURATION = Xindice.PROP_XINDICE_CONFIGURATION;
  +
  +    /**
        * Prefix used to denote XML:DB URI's that should use this driver
        */
       public static final String DRIVER_NAME = "xindice-embed";
  @@ -99,18 +148,18 @@
        */
       private static final String CONFORMANCE_LEVEL = "0";
   
  +
       /**
  -     * Database instance
  +     * Database configuration location.
  +     * Null if built-in configuration was used.
        */
  -    private Database database;
  +    private String configFile;
  +
   
       /**
  -     * Creates new <code>DatabaseImpl</code> instance. The configuration is
  -     * loaded from the file defined in the PROP_XINDICE_CONFIGURATION system
  -     * variable.
  +     * Creates new <code>DatabaseImpl</code> instance.
        */
  -    public DatabaseImpl() throws IOException, XindiceException {
  -        init();
  +    public DatabaseImpl() {
       }
   
       /**
  @@ -119,101 +168,151 @@
        *
        * This allows to pass properties such as PROP_XINDICE_CONFIGURATION
        * to this instance. Usually this is done by instantiating not this
  -     * class, but <code>org.apache.xindice.client.xmldb.DatabaseImpl</code>,
  +     * class, but {@link org.apache.xindice.client.xmldb.DatabaseImpl},
        * set all the necessary parameters, and then get a collection.
        *
        * @param config from which the initial parameters for this
        *        DatabaseImpl object are copied.
        */
  -    public DatabaseImpl(CommonConfigurable config) throws IOException, XindiceException {
  +    public DatabaseImpl(CommonConfigurable config) {
           super(config);
  -        init();
       }
   
       /**
  -     * Init this database instance.
  -     *
  -     * This is only a temporarly solution since the question of a new init
  -     * method is raised in the xmldb:api group. Another solution could be to
  -     * use the Configurable interface and only create the database when the
  -     * getCollection method is called.
  +     * Get named database instance. If database is not loaded yet, load it.
        *
  -     * @throws IOException
  -     * @throws XindiceException
  +     * @throws XMLDBException if configuration for this database is not found,
  +     *                        or could not be read.
        */
  -    private void init() throws IOException, XindiceException {
  -        Configuration config = loadConfiguration();
  +    private Database getDatabase(String dbName, String uri) throws XMLDBException {
  +        Database database = Database.getDatabase(dbName);
  +        if (database == null) {
  +            Configuration dbConfig = getConfiguration(dbName);
  +            if (log.isDebugEnabled()) {
  +                log.debug("Mounting database: '" + dbName + "'");
  +            }
   
  -        this.database = Database.getDatabase(config);
  -        if (null == this.database) {
  -            log.fatal("Unable to configure database");
  -            throw new XindiceException("Unable to configure database");
  -        }
  +            if (dbConfig == null) {
  +                throw new XMLDBException(ErrorCodes.NO_SUCH_DATABASE,
  +                                         "Database '" + dbName + "' not found: " + uri);
  +            }
   
  -        if (log.isDebugEnabled()) {
  -            log.info("Database name: '" + this.database.getName() + "'");
  +            database = Database.getDatabase(dbConfig);
  +            if (log.isDebugEnabled()) {
  +                log.info("Mounted database: '" + database.getName() + "'");
  +            }
           }
  -    }
  -
  -    protected Configuration loadConfiguration() throws IOException, XindiceException  {
  -        Configuration config;
  -        String configDir = null;
   
  -        String configFile = null;
  -        try {
  -            // Try configuration first
  -            configFile = getProperty(Xindice.PROP_XINDICE_CONFIGURATION);
  -        } catch (XMLDBException ignored) {
  -        }
  -        if (configFile == null) {
  -            // Fallback to system property
  -            configFile = System.getProperty(Xindice.PROP_XINDICE_CONFIGURATION);
  -        }
  +        return database;
  +    }
   
  -        if (configFile != null && !configFile.equals("")) {
  -            if (log.isInfoEnabled()) {
  -                log.info("Specified configuration file: '" + configFile + "'");
  -            }
  -            FileInputStream configXMLFile = new FileInputStream(configFile);
  +    /**
  +     * Get configuration for the named database
  +     */
  +    protected Configuration getConfiguration(String dbName) throws XMLDBException  {
  +        Configuration config = loadConfiguration();
   
  -            config = new Configuration(DOMParser.toDocument(configXMLFile), false);
  -            configDir = new File(configFile).getAbsoluteFile().getParent();
  -        } else {
  -            if (log.isInfoEnabled()) {
  -                log.info("No configuration file specified, going with the default configuration");
  +        // Find database config with the given database name
  +        Configuration[] roots = config.getChildren("root-collection");
  +        config = null;
  +        for (int i = 0; i < roots.length; i++) {
  +            if (dbName.equals(roots[i].getAttribute(Database.NAME))) {
  +                config = roots[i];
  +                break;
               }
  -
  -            config = new Configuration(DOMParser.toDocument(Xindice.DEFAULT_CONFIGURATION), false);
           }
   
  -        config = config.getChild("root-collection", false);
  +        if (config == null) {
  +            return null;
  +        }
   
  +        // Figure out database root
           String dbRoot = config.getAttribute(Database.DBROOT, Database.DBROOT_DEFAULT);
           if (!new File(dbRoot).isAbsolute()) {
  -            // Let's see if the property was specified.
  +            // Let's see if the XINDICE_DB_HOME property was specified.
               String home = null;
               try {
                   // Try configuration first
  -                home = getProperty(Xindice.PROP_XINDICE_DB_HOME);
  +                home = getProperty(PROP_XINDICE_DB_HOME);
               } catch (XMLDBException ignored) {
               }
               if (home == null) {
                   // Fallback to system property
  -                home = System.getProperty(Xindice.PROP_XINDICE_DB_HOME);
  +                home = System.getProperty(SYSPROP_XINDICE_DB_HOME);
               }
   
               if (home != null) {
  -                dbRoot = new File(home + File.separator + dbRoot).getCanonicalPath();
  -            } else if (configDir != null) {
  -                dbRoot = configDir + File.separator + dbRoot;
  +                try {
  +                    dbRoot = new File(home + File.separator + dbRoot).getCanonicalPath();
  +                } catch (IOException e) {
  +                    log.warn("getCanonicalPath failed", e);
  +                    dbRoot = new File(home + File.separator + dbRoot).getAbsolutePath();
  +                }
  +            } else if (configFile != null) {
  +                dbRoot = new File(configFile).getAbsoluteFile().getParent() + File.separator + dbRoot;
               } else {
                   log.warn("The database configuration file is not specified and there was no "
  -                         + Xindice.PROP_XINDICE_DB_HOME + " property set, "
  +                         + SYSPROP_XINDICE_DB_HOME + " property set, "
                            + "so Xindice was unable to determine a database location. "
                            + "Database will be created relative to the current directory.");
  -                dbRoot = new File("." + File.separator + dbRoot).getCanonicalPath();
  +                try {
  +                    dbRoot = new File("." + File.separator + dbRoot).getCanonicalPath();
  +                } catch (IOException e) {
  +                    log.warn("getCanonicalPath failed", e);
  +                    dbRoot = new File("." + File.separator + dbRoot).getAbsolutePath();
  +                }
  +            }
  +            try {
  +                config.setAttribute(Database.DBROOT, dbRoot);
  +            } catch (ReadOnlyException ignore) {
  +            }
  +        }
  +
  +        return config;
  +    }
  +
  +    private Configuration loadConfiguration() throws XMLDBException {
  +        Configuration config;
  +
  +        if (configFile == null) {
  +            try {
  +                // Try configuration first
  +                configFile = getProperty(PROP_XINDICE_CONFIGURATION);
  +            } catch (XMLDBException ignored) {
  +            }
  +            if (configFile == null) {
  +                // Fallback to system property
  +                configFile = System.getProperty(SYSPROP_XINDICE_CONFIGURATION);
  +            }
  +            if ("".equals(configFile)) {
  +                configFile = null;
  +            }
  +        }
  +
  +        if (configFile != null) {
  +            if (log.isInfoEnabled()) {
  +                log.info("Specified configuration file: '" + configFile + "'");
  +            }
  +            try {
  +                FileInputStream configXMLFile = new FileInputStream(configFile);
  +                config = new Configuration(DOMParser.toDocument(configXMLFile), false);
  +            } catch (XindiceException e) {
  +                throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR,
  +                                         "Unable to parse database configuration file: " + configFile, e);
  +            } catch (FileNotFoundException e) {
  +                throw new XMLDBException(ErrorCodes.UNKNOWN_ERROR,
  +                                         "Database configuration file not found: " + configFile);
  +            }
  +        } else {
  +            if (log.isInfoEnabled()) {
  +                log.info("No configuration file specified, going with the default configuration");
  +            }
  +
  +            try {
  +                config = new Configuration(DOMParser.toDocument(Xindice.DEFAULT_CONFIGURATION), false);
  +            } catch (XindiceException e) {
  +                throw new XindiceRuntimeException("Unable to parse default database configuration", e);
               }
  -            config.setAttribute(Database.DBROOT, dbRoot);
           }
   
           return config;
  @@ -302,17 +401,12 @@
               }
           }
   
  -        // TODO: Is this correct behavior?
  -        if (!database.getName().equals(dbName)) {
  -            throw new XMLDBException(ErrorCodes.NO_SUCH_DATABASE,
  -                                     "Unknown database (must be '" + database.getName() + "'): " + uri);
  -        }
  -
  +        Database database = getDatabase(dbName, uri);
           try {
               return new CollectionImpl(database, colName);
           } catch (XMLDBException e) {
               if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) {
  -                // per getCollection contract, return null if not found
  +                // Per getCollection contract, return null if not found
                   return null;
               }
               throw e;