All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xmldb.api.DatabaseManager Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 *  The XML:DB Initiative Software License, Version 1.0
 *
 *
 * Copyright (c) 2000-2003 The XML:DB Initiative.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        XML:DB Initiative (http://www.xmldb.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The name "XML:DB Initiative" must not be used to endorse or
 *    promote products derived from this software without prior written
 *    permission. For written permission, please contact [email protected].
 *
 * 5. Products derived from this software may not be called "XML:DB",
 *    nor may "XML:DB" appear in their name, without prior written
 *    permission of the XML:DB Initiative.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the XML:DB Initiative. For more information
 * on the XML:DB Initiative, please see .
 */

package org.xmldb.api;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.locks.StampedLock;

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

/**
 * DatabaseManager is the entry point for the API and enables you to get the 
 * initial Collection references necessary to do anything useful with the API.
 * DatabaseManager is intended to be
 * provided as a concrete implementation in a particular programming
 * language. Individual language mappings should define the exact syntax and
 * semantics of its use. 
 */
public class DatabaseManager
{
   protected static final String URI_PREFIX = "xmldb:"; 

   static final Properties properties = new Properties();
   static final StampedLock dbLock = new StampedLock();
   static final Map databases = new HashMap<>(5);

   static boolean strictRegistrationBehavior = Boolean.getBoolean("org.xmldb.api.strictRegistrationBehavior");

   /**
    * Returns a list of all available Database implementations 
    * that have been registered with this DatabaseManager.
    *
    * @return An array of Database instances. 
    *  One for each Database registered
    *  with the DatabaseManager. If no Database
    *  instances exist then an empty array is returned.
    */ 
   public static Database[] getDatabases() {
      // try optimistic read first
      long stamp = dbLock.tryOptimisticRead();
      if (stamp > 0) {
          final Database[] result = databases.values().toArray(new Database[0]);
          if (dbLock.validate(stamp)) {
              return result;
          }
      }

      // fallback to locking read
      stamp = dbLock.readLock();
      try {
         return databases.values().toArray(new Database[0]);
      } finally {
         dbLock.unlockRead(stamp);
      }
   }

   /**
    * Registers a new Database implementation with the
    * DatabaseManager. 
    *
    * @param database The database instance to register.
    * @throws XMLDBException with expected error codes.
    *  ErrorCodes.VENDOR_ERROR for any vendor
    *  specific errors that occur.
    *  ErrorCodes.INVALID_DATABASE if the provided Database
    *   instance is invalid.
    */
   public static void registerDatabase(final Database database) throws XMLDBException {
      final String[] databaseNames = database.getNames();
      // we need at least one suitable name for this instance
      if (databaseNames == null || databaseNames.length == 0 || databaseNames[0].isEmpty()) {
         throw new XMLDBException(ErrorCodes.INVALID_DATABASE);
      }

      final long stamp = dbLock.writeLock();
      try {
          // put all names of this instance into the databases map
          for (final String databaseName : databaseNames) {
              updateDatabases(databaseName, database);
          }
      } finally {
          dbLock.unlockWrite(stamp);
      }

   }

   private static void updateDatabases(final String databaseName, final Database database) throws XMLDBException {
      final Database existing = databases.putIfAbsent(databaseName, database);
      if (existing != null && existing != database && strictRegistrationBehavior) {
          throw new XMLDBException(ErrorCodes.INSTANCE_NAME_ALREADY_REGISTERED);
      }
   }

/**
    * Deregisters a Database implementation from the DatabaseManager. Once a
    * Database has been deregistered it can no longer be used to handle
    * requests.
    *
    * @param database The Database instance to deregister.
    * @throws XMLDBException with expected error codes.
    *  ErrorCodes.VENDOR_ERROR for any vendor
    *  specific errors that occur.
    */
   public static void deregisterDatabase(final Database database)
         throws XMLDBException {
      final long stamp = dbLock.writeLock();
      try {
        for (Iterator dbIterator = databases.values().iterator(); dbIterator.hasNext();) {
          if (database.equals(dbIterator.next())) {
            dbIterator.remove();
          }
        }
      } finally {
        dbLock.unlockWrite(stamp);
      }
    }
   
   /**
    * Retrieves a Collection instance from the database for the 
    * given URI. The format of the majority of the URI is database 
    * implementation specific however the uri must begin with characters xmldb:
    * and be followed by the name of the database instance as returned by 
    * Database.getName() and a colon
    * character. An example would be for the database named "vendordb" the URI
    * handed to getCollection would look something like the following.
    * xmldb:vendordb://host:port/path/to/collection. The xmldb:
    * prefix will be removed from the URI prior to handing the URI to the
    * Database instance for handling.
    *
    * This method is called when no authentication is necessary for the
    * database.
    *
    * @param uri The database specific URI to use to locate the collection.
    * @return A Collection instance for the requested collection or
    *  null if the collection could not be found.
    * @throws XMLDBException with expected error codes.
    *  ErrorCodes.VENDOR_ERROR for any vendor
    *  specific errors that occur.
    *  ErrroCodes.INVALID_URI If the URI is not in a valid format. 
    *  ErrroCodes.NO_SUCH_DATABASE If a Database
    *    instance could not be found to handle the provided URI.
    */
   public static Collection getCollection(final String uri)
         throws XMLDBException {
      return getCollection(uri, null, null);
   }

      /**
    * Retrieves a Collection instance from the database for the 
    * given URI. The format of the majority of the URI is database 
    * implementation specific however the uri must begin with characters xmldb:
    * and be followed by the name of the database instance as returned by 
    * Database.getName() and a colon
    * character. An example would be for the database named "vendordb" the URI
    * handed to getCollection would look something like the following.
    * xmldb:vendordb://host:port/path/to/collection. The xmldb:
    * prefix will be removed from the URI prior to handing the URI to the
    * Database instance for handling.
    *
    * @param uri The database specific URI to use to locate the collection.
    * @param username The username to use for authentication to the database or
    *    null if the database does not support authentication.
    * @param password The password to use for authentication to the database or
    *    null if the database does not support authentication.
    * @return A Collection instance for the requested collection or
    *  null if the collection could not be found.
    * @throws XMLDBException with expected error codes.
    *  ErrorCodes.VENDOR_ERROR for any vendor
    *  specific errors that occur.
    *  ErrroCodes.INVALID_URI If the URI is not in a valid format. 
    *  ErrroCodes.NO_SUCH_DATABASE If a Database
    *    instance could not be found to handle the provided URI.
    *  ErrroCodes.PERMISSION_DENIED If the username
    *    and password were not accepted by the database.
    */
   public static Collection getCollection(final String uri,
         final String username, final String password) throws XMLDBException {
      final Database db = getDatabase(uri);
      return db.getCollection(stripURIPrefix(uri), username, password);
   }

   /**
    * Returns the Core Level conformance value for the provided URI. The current
    * API defines valid resuls of "0" or "1" as defined in the XML:DB API
    * specification.
    *
    * @param uri The database specific URI to use to locate the collection.
    * @return The XML:DB Core Level conformance for the uri.
    * @throws XMLDBException with expected error codes.
    *  ErrorCodes.VENDOR_ERROR for any vendor
    *  specific errors that occur.
    *  ErrroCodes.INVALID_URI If the URI is not in a valid format. 
    *  ErrroCodes.NO_SUCH_DATABASE If a Database
    *    instance could not be found to handle the provided URI.
    */
   public static String getConformanceLevel(final String uri) throws XMLDBException {
      final Database database = getDatabase(uri);
      return database.getConformanceLevel();
   }

   /**
    * Retrieves a property that has been set for the DatabaseManager.
    *
    * @param name The property name
    * @return The property value
    */
   public static String getProperty(final String name) {
      return properties.getProperty(name);
   }

   /**
    * Sets a property for the DatabaseManager.
    *
    * @param name The property name
    * @param value The value to set.
    */   
   public static void setProperty(final String name, final String value) {
      properties.put(name, value);
   }

   /**
    * Retrieves the registered Database instance associated with the provided 
    * URI.
    *
    * @param uri The uri containing the database reference.
    * @return the requested Database instance.
    * @throws XMLDBException if an error occurs whilst getting the database
    */
   protected static Database getDatabase(final String uri) throws XMLDBException {
      if (!uri.startsWith(URI_PREFIX)) {
         throw new XMLDBException(ErrorCodes.INVALID_URI);
      }

      final int end = uri.indexOf(":", URI_PREFIX.length());
      if (end == -1) {
         throw new XMLDBException(ErrorCodes.INVALID_URI);
      }

      final String databaseName = uri.substring(URI_PREFIX.length(), end);

      // try optimistic read first
      long stamp = dbLock.tryOptimisticRead();
      if (stamp > 0) {
          final Database db = databases.get(databaseName);
          if (dbLock.validate(stamp)) {
              if (db == null) {
                  throw new XMLDBException(ErrorCodes.NO_SUCH_DATABASE);
              }
              return db;
          }
      }

      // fallback to locking read
      final Database db;
      stamp = dbLock.readLock();
      try {
          db = databases.get(databaseName); 
      } finally {
          dbLock.unlockRead(stamp);
      }

      if (db == null) {
         throw new XMLDBException(ErrorCodes.NO_SUCH_DATABASE);
      }

      return db;
   }
   
   /**
    * Removes the URI_PREFIX from the front of the URI. This is so the database
    * can focus on handling its own URIs.
    *
    * @param uri The full URI to strip.
    * @return The database specific portion of the URI.
    * @throws XMLDBException if an error occurs whilst stripping the URI prefix
    */
   protected static String stripURIPrefix(final String uri) throws XMLDBException {
      if (!uri.startsWith(URI_PREFIX)) {
         throw new XMLDBException(ErrorCodes.INVALID_URI);
      }

      return uri.substring(URI_PREFIX.length());
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy