/*
* $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/common/Namespace.java,v 1.41 2001/10/23 13:03:27 cmlenz Exp $
* $Revision: 1.41 $
* $Date: 2001/10/23 13:03:27 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. 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 acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* 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 Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.slide.common;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Enumeration;
import java.util.Stack;
import java.util.Date;
import java.io.Reader;
import java.io.Writer;
import java.io.FileReader;
import java.io.IOException;
import javax.transaction.TransactionManager;
import javax.transaction.Transaction;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.NotSupportedException;
import javax.transaction.xa.XAResource;
import org.apache.slide.structure.*;
import org.apache.slide.content.*;
import org.apache.slide.lock.*;
import org.apache.slide.security.*;
import org.apache.slide.store.*;
import org.apache.slide.transaction.SlideTransactionManager;
import org.apache.slide.authenticate.CredentialsToken;
import org.apache.slide.util.conf.Configuration;
import org.apache.slide.util.conf.ConfigurationException;
import org.apache.slide.util.logger.Logger;
/**
* A Namespace contains a hierarchically organized tree of information.
*
* <p>
* Objects in the namespace are generally referred to as <i>Nodes</i>. Nodes
* may have a parent, children, content and meta-data. They can also be
* versioned (so that multiple revisions of the object's content and
* metadata are stored) and locked (so that only specific principals are
* allowed to read or modify the object). In addition, access control
* information can be assigned to every node.
* </p>
* <p>
* Nodes in the hierarchy are identified by their URI (Unique Resource
* Identifier). A URI is analogous to a file path in traditional file
* systems. For example:
* <pre>
* /users/john/documents/my_document.txt
* </pre>
* As you can see, the slash ("/") is used to separate nodes in the path.
* </p>
* <p>
* Client applications can not access a Namespace object directly. Instead,
* access must be requested from the {@link Domain Domain}, which will hand
* out a proxy object ({@link NamespaceAccessToken NamespaceAccessToken})
* that enables the client application to access the namespace using the
* helpers.
* </p>
* <p>
* Namespaces are necessarily self-contained. What this means is that a
* namespace cannot reference or contain links to another namespace. A
* namespace is typically assigned per-application, which effectively
* isolates it's data and security context from those of other applications.
* </p>
*
* @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
* @author Dirk Verbeeck
* @version $Revision: 1.41 $
*/
public final class Namespace {
// -------------------------------------------------------------- Constants
public static final String REFERENCE = "reference";
public static final String NODE_STORE = "nodestore";
public static final String SECURITY_STORE = "securitystore";
public static final String LOCK_STORE = "lockstore";
public static final String REVISION_DESCRIPTORS_STORE =
"revisiondescriptorsstore";
public static final String REVISION_DESCRIPTOR_STORE =
"revisiondescriptorstore";
public static final String CONTENT_STORE = "contentstore";
// ----------------------------------------------------- Instance Variables
/**
* Namespace name.
*/
private String name;
/**
* Static Vector which holds a reference, and provides access to all
* the services instances used by the Slide namespace.
*/
private transient Vector connectedServices;
/**
* Registered DescriptorStores on this Namespace.
*/
private transient Hashtable stores;
/**
* Current namespace configuration.
*/
private NamespaceConfig config;
/**
* Uri cache.
*/
private Hashtable uriCache;
/**
* Default descriptors store classname.
*/
private String defaultStoreClassname =
"org.apache.slide.store.StandardStore";
/**
* Transaction manager associated with this namespace.
*/
private TransactionManager transactionManager =
new SlideTransactionManager();
/**
* Log channel for logger
*/
private final static String LOG_CHANNEL = Namespace.class.getName();
/**
* Logger.
*/
private Logger logger;
/**
* Application logger.
*/
private Logger applicationLogger;
// ------------------------------------------------------------ Constructor
/**
* Constructor.
*/
Namespace() {
stores = new Hashtable();
connectedServices = new Vector();
name = new String();
uriCache = new Hashtable();
}
// ------------------------------------------------------------- Properties
/**
* Sets the qualified name of the namespace.
*
* @param name Name of the namespace
*/
public void setName(String name) {
this.name = name;
}
/**
* Gets the qulified name of the namespace.
*
* @return String Namespace name
*/
public String getName() {
return name;
}
/**
* Returns the namespace configuration.
*
* @return NamespaceConfig Namespace configuration
*/
public NamespaceConfig getConfig() {
return config;
}
/**
** Enumerate all scopes managed by this namespace.
**
** @return return an enumeration of all scopes
**/
public Enumeration enumerateScopes() {
return stores.keys();
}
/**
* Transaction manager accessor.
*/
public TransactionManager getTransactionManager() {
return transactionManager;
}
/**
* Return the current logger.
*/
public Logger getLogger() {
if (logger != null)
return logger;
else
return Domain.getLogger();
}
/**
* Set the logger used by this namespace.
*/
public void setLogger(Logger logger) {
this.logger = logger;
if (transactionManager instanceof SlideTransactionManager) {
((SlideTransactionManager) transactionManager).setLogger(logger);
}
}
/**
* Return the current application logger.
*/
public Logger getApplicationLogger() {
if (applicationLogger != null)
return applicationLogger;
else if (logger != null)
return logger;
else
return Domain.getLogger();
}
/**
* Set the logger used by this namespace.
*/
public void setApplicationLogger(Logger logger) {
this.applicationLogger = applicationLogger;
}
// --------------------------------------------------------- Public Methods
/**
* Used to register a Store in the namespace for the specified scope.
* First, the function instantiate the Store, then gives it
* its init parameters. It is then stored in the stores
* Hashtable, associated with the given scope.
*
* @param storeClass Class of the Data Source
* @param parameters Init parameters for the Data Source
* @param scope Scope for which the Data Source is registered
* @param childStores Instances of the typed stores
* @exception ServiceRegistrationFailed An error occured during
* instantiation of the service
* @exception ServiceParameterErrorException Incorrect service parameter
* @exception ServiceParameterMissingException Service parameter missing
*/
public void registerStore(String storeName, Class storeClass,
Hashtable parameters, Scope scope,
Hashtable childStores)
throws ServiceRegistrationFailedException,
ServiceParameterErrorException, ServiceParameterMissingException {
if (!stores.containsKey(scope)) {
try {
Store store = (Store) storeClass.newInstance();
store.setName(storeName);
store.setParameters(parameters);
stores.put(scope, store);
// Now assigning the child stores
Object nodeStore = childStores.get(NODE_STORE);
if (nodeStore instanceof String) {
// Resolving reference
store.setNodeStore((NodeStore) childStores.get(nodeStore));
} else {
store.setNodeStore((NodeStore) nodeStore);
}
Object securityStore = childStores.get(SECURITY_STORE);
if (securityStore instanceof String) {
// Resolving reference
store.setSecurityStore
((SecurityStore) childStores.get(securityStore));
} else {
store.setSecurityStore
((SecurityStore) securityStore);
}
Object lockStore = childStores.get(LOCK_STORE);
if (lockStore instanceof String) {
store.setLockStore
((LockStore) childStores.get(lockStore));
} else {
store.setLockStore((LockStore) lockStore);
}
Object revisionDescriptorsStore = childStores
.get(REVISION_DESCRIPTORS_STORE);
if (revisionDescriptorsStore instanceof String) {
store.setRevisionDescriptorsStore
((RevisionDescriptorsStore) childStores
.get(revisionDescriptorsStore));
} else {
store.setRevisionDescriptorsStore
((RevisionDescriptorsStore) revisionDescriptorsStore);
}
Object revisionDescriptorStore = childStores
.get(REVISION_DESCRIPTOR_STORE);
if (revisionDescriptorStore instanceof String) {
store.setRevisionDescriptorStore
((RevisionDescriptorStore) childStores
.get(revisionDescriptorStore));
} else {
store.setRevisionDescriptorStore
((RevisionDescriptorStore) revisionDescriptorStore);
}
Object contentStore = childStores.get(CONTENT_STORE);
if (contentStore instanceof String) {
// Resolving reference
store.setContentStore
((ContentStore) childStores.get(contentStore));
} else {
store.setContentStore((ContentStore) contentStore);
}
// set the scope in the father and child stores
store.setScope(scope);
} catch(InstantiationException e) {
throw new ServiceRegistrationFailedException
(storeClass);
} catch(IllegalAccessException e) {
throw new ServiceRegistrationFailedException
(storeClass);
} catch(NullPointerException e) {
throw new ServiceRegistrationFailedException
(storeClass);
} catch(ClassCastException e) {
// TEMP
getLogger().log(e,LOG_CHANNEL, Logger.ERROR);
// --TEMP
throw new ServiceRegistrationFailedException
(storeClass);
}
}
}
/**
* At the end of the service registration, this service is called to
* perform any required initialization task.
*
* @exception ServicesInitializationFailedException One or more
* exception occured while initializing services
*/
public void initializeServices()
throws ServicesInitializationFailedException {
// We create the nested exception which will hold all thrown exception
// during the initialization process.
ServicesInitializationFailedException nestedException
= new ServicesInitializationFailedException();
// Initializing DesciptorsStores
Enumeration serviceList = stores.elements();
while (serviceList.hasMoreElements()) {
Service service = (Service) serviceList.nextElement();
try {
getLogger().log("Initializing Store " + service,LOG_CHANNEL,Logger.INFO);
service.setNamespace(this);
service.initialize(new NamespaceAccessTokenImpl(this));
} catch (ServiceInitializationFailedException e) {
// We add the exception which just occured to the
// nested exception
nestedException.addException(e);
}
}
// If the nested exception is not empty, we throw it.
if (!nestedException.isEmpty()) {
throw nestedException;
}
}
/**
* Reinitialize namespace.
*/
public void clearNamespace() {
stores.clear();
}
/**
* Connects a data source on demand.
*
* @param service Service on which a connection attempt will be made
* @exception ServiceConnectionFailedException Error connecting service
* @exception ServiceAccessException Unspecified low level service
* access exception
*/
public void connectService(Service service)
throws ServiceConnectionFailedException, ServiceAccessException {
// Try to connect ...
boolean newConnection = service.connectIfNeeded();
// If successfull (ie, no exception was thrown), we add it to the list
// of the connected components.
if (newConnection) {
connectedServices.addElement(service);
}
}
/**
* Disconnects all services.
*
* @exception ServicesShutDownFailedException Error disconnecting one or
* more services
*/
public void disconnectServices()
throws ServicesShutDownFailedException {
// We create the nested exception which will hold all thrown exception
// during shut down of services.
ServicesShutDownFailedException nestedException
= new ServicesShutDownFailedException();
for (int i=0; i<connectedServices.size(); i++) {
try {
Service service = (Service) connectedServices.elementAt(i);
if (service.isConnected()) {
getLogger().log("Shutting down service " + service,LOG_CHANNEL,Logger.INFO);
service.disconnect();
}
} catch (ServiceDisconnectionFailedException e) {
nestedException.addException(e);
} catch (ServiceAccessException e) {
nestedException.addException(e);
}
}
connectedServices.removeAllElements();
// If the nested exception is not empty, we throw it.
if (!nestedException.isEmpty()) {
throw nestedException;
}
}
/**
* Remove a Store from the registry.
*
* @param scope Scope to disconnect
* @exception ServiceDisconnctionFailedException Error disconnecting
* DescriptorsStore
* @exception ServiceAccessException Unspecified error during
* service access
*/
public void unregisterStore(Scope scope)
throws ServiceDisconnectionFailedException, ServiceAccessException {
if (stores.containsKey(scope)) {
Store store = (Store) stores.get(scope);
if (store.isConnected()) {
store.disconnect();
connectedServices.removeElement(store);
}
stores.remove(scope);
store = null;
}
}
/**
* Get the Data Source associated with the given scope, if any.
* In contrary to the retrieveStore method, this methos does not
* perform a connection.
*
* @param scope Scope to match
*/
public Store getStore(Scope scope) {
Store store = null;
if (stores.containsKey(scope)) {
store = (Store) stores.get(scope);
}
return store;
}
/**
* Get the Data Source associated with the given scope, if any and
* connect to the store.
*
* @param scope Scope to match
* @exception ServiceConnectionFailedException Connection to Store failed
* @exception ServiceAccessException Unspecified service access exception
*/
public Store retrieveStore(Scope scope)
throws ServiceConnectionFailedException, ServiceAccessException {
Store store = getStore(scope);
if (store != null) {
connectService(store);
}
return store;
}
/**
* Builds a new uri object to access this namespace. This call will
* return a Uri which doesn't have its token field set. The store should
* accept such Uri as valid, and bypass any check that is made based on the
* state.
*
* @param uri Requested Uri
* @return Uri
*/
public Uri getUri(String uri) {
return getUri(null, uri);
}
/**
* Builds a new uri object to access this namespace.
*
* @param token SlideToken
* @param uri Requested Uri
* @return Uri
*/
public Uri getUri(SlideToken token, String uri) {
return getUri(token, uri, token==null
?false
:token.isForceStoreEnlistment());
}
/**
* Builds a new uri object to access this namespace.
*
* @param token SlideToken
* @param uri Requested Uri
* @param forcedEnlistment may differ from the value set in token
* @return Uri
*/
public Uri getUri(SlideToken token, String uri, boolean forcedEnlistment) {
Uri result = null;
Object temp = null;
temp = uriCache.get(uri);
if (temp == null) {
result = new Uri(token, this, uri);
uriCache.put(uri, result);
if (uriCache.size() > 10000) {
clearUriCache();
}
} else {
result = (Uri) temp;
result = result.cloneObject();
result.reconnectServices();
result.setToken(token);
}
// if a different forceEnlistment value want to be used
// wrap the used token to reflect the different value
if (token != null && token.isForceStoreEnlistment() != forcedEnlistment) {
result.setToken(new SlideTokenWrapper(token, forcedEnlistment));
}
return result;
}
/**
* Clear uri cache.
*/
void clearUriCache() {
uriCache.clear();
}
/**
* Get content interceptors associated with this namespace.
*/
public ContentInterceptor[] getContentInterceptors() {
return config.getContentInterceptors();
}
// -------------------------------------------------------- Package Methods
/**
* Parses the contents of the specified definition object, and uses that
* info to initialize the namespace.
*
* @param definition Definiton of the scopes and stores of
* the namespace
* @exception SlideException Something went wrong during registry or
* services initialization
* @exception ConfigurationException Error parsing configuration file
*/
void loadDefinition(Configuration definition)
throws SlideException, ConfigurationException {
getLogger().log("Loading namespace definition",LOG_CHANNEL,Logger.INFO);
// Loading stores
Hashtable storesClass = new Hashtable();
Hashtable storesParameters = new Hashtable();
Hashtable childStores = new Hashtable();
Enumeration storeDefinitions =
definition.getConfigurations("store");
while (storeDefinitions.hasMoreElements()) {
loadStoreDefinition
((Configuration) storeDefinitions.nextElement(),
storesClass, storesParameters, childStores);
}
Enumeration scopeDefinitions =
definition.getConfigurations("scope");
while (scopeDefinitions.hasMoreElements()) {
loadScopeDefinition
((Configuration) scopeDefinitions.nextElement(),
storesClass, storesParameters, childStores);
}
// Initialize all loaded services.
initializeServices();
}
/**
* Parses the contents of the specified reader, and uses that info to
* initialize the specified Slide namespace.
*
* @param namespaceBaseDataDefinition Namespace base data
* @exception SlideException Something went wrong during registry or
* services initialization
*/
void loadBaseData(Configuration namespaceBaseDataDefinition)
throws SlideException, ConfigurationException {
getLogger().log("Loading namespace " + getName() + " base data",LOG_CHANNEL,Logger.INFO);
// Load Namespace Base Data
try {
// start transaction for temp object creation
getTransactionManager().begin();
// First, we create the root node
Uri rootUri = getUri("/");
SubjectNode rootNode = new SubjectNode("/");
NodePermission allAccess = new NodePermission("/", "/", "/");
try {
rootUri.getStore().createObject(rootUri, rootNode);
} catch (ObjectAlreadyExistsException e) {
// abort the failed transaction
getTransactionManager().rollback();
// start a new one to continue processing
getTransactionManager().begin();
}
rootUri.getStore().grantPermission(rootUri, allAccess);
// Create a dummy action
Uri tempActionUri = getUri("/tempaction");
ActionNode tempAction = new ActionNode("/tempaction");
tempActionUri.getStore().createObject(tempActionUri, tempAction);
// end transaction for temp object creation
getTransactionManager().commit();
getLogger().log("Init namespace " + getName() + " configuration",LOG_CHANNEL,Logger.INFO);
// Create the dummy configuration
config.initializeAsDummyConfig(this);
// Create the Access token
NamespaceAccessToken token = new NamespaceAccessTokenImpl(this);
// start the transaction, NOTE some operations are outside this TA
token.begin();
getLogger().log("Import data into namespace " + getName(),LOG_CHANNEL,Logger.INFO);
token.importData
(new SlideTokenImpl(new CredentialsToken(new String("/"))),
namespaceBaseDataDefinition);
// end the transaction, NOTE some operations are outside this TA
token.commit();
// start transaction for temp object removal
getTransactionManager().begin();
getLogger().log("Finish init namespace " + getName() + " configuration",LOG_CHANNEL,Logger.INFO);
// Then, destroy the temp action
tempActionUri.getStore().removeObject(tempActionUri, tempAction);
// And remove the all permission from the root node
rootNode =
(SubjectNode) rootUri.getStore().retrieveObject(rootUri);
rootUri.getStore().revokePermission(rootUri, allAccess);
rootUri.getStore().storeObject(rootUri, rootNode);
// end transaction for temp object removal
getTransactionManager().commit();
} catch (SlideException e) {
// If that occurs, then most likely the base config was
// already done before
getLogger().log("Namespace base configuration was already done before",LOG_CHANNEL,Logger.INFO);
try {
if (getTransactionManager().getStatus()==Status.STATUS_ACTIVE)
getTransactionManager().rollback();
}
catch (SystemException ex) {
getLogger().log("Could not rollback namespace base configuration: " + ex.toString(),LOG_CHANNEL,Logger.WARNING);
}
} catch (Exception e) {
getLogger().log("Unable to read Namespace base configuration file : ",LOG_CHANNEL,Logger.ERROR);
getLogger().log(e,LOG_CHANNEL, Logger.ERROR);
// Unable to load the base configuration XML file.
// Log the event, and hope it was already done before.
try {
if (getTransactionManager().getStatus()==Status.STATUS_ACTIVE)
getTransactionManager().rollback();
}
catch (SystemException ex) {
getLogger().log("Could not rollback namespace base configuration after load error: " + ex.toString(),LOG_CHANNEL,Logger.WARNING);
}
}
}
/**
* Parses the contents of the specified reader, and uses that info to
* initialize the specified Slide namespace.
*
* @param namespaceBaseDataDefinition Namespace base data
* @exception SlideException Something went wrong during registry or
* services initialization
*/
void loadConfiguration(Configuration namespaceConfigurationDefinition)
throws SlideException {
getLogger().log("Loading namespace " + getName() + " configuration",LOG_CHANNEL,Logger.INFO);
// Load Namespace Config
config = new NamespaceConfig();
config.initializeNamespaceConfig(this,
namespaceConfigurationDefinition);
}
/**
* Parses the contents of the specified reader, and uses that info to
* initialize the specified Slide namespace.
*
* @param namespaceConfigurationDefinition Namespace configuration
* @exception SlideException Something went wrong during registry or
* services initialization
*/
void loadParameters(Configuration namespaceConfigurationDefinition)
throws SlideException {
getLogger().log("Loading namespace " + getName() + " parameters",LOG_CHANNEL,Logger.INFO);
// Load Namespace Config
config = new NamespaceConfig();
config.initializeNamespaceParameters(this,
namespaceConfigurationDefinition);
}
// -------------------------------------------------------- Private Methods
/**
* Parse the store definition.
*
* @param storeDefinition store definition
* @param storesClass Class names of the stores
* @param storesParameters Parameters of the stores
* @param childStores Child stores
* @exception ConfigurationException Error parsing configuration file
* @exception SlideException Error loading the specified class
*/
private void loadStoreDefinition
(Configuration storeDefinition,
Hashtable storesClass,
Hashtable storesParameters,
Hashtable childStores)
throws ConfigurationException, SlideException {
String storeName = storeDefinition.getAttribute("name");
String storeClassname = defaultStoreClassname;
try {
storeClassname = storeDefinition.getAttribute("classname");
} catch (ConfigurationException e) {
}
Enumeration storeParametersDefinitions =
storeDefinition.getConfigurations("parameter");
// Load descriptors store class
Class storeClass = null;
try {
storeClass = Class.forName(storeClassname);
} catch (Exception e) {
getLogger().log(e,LOG_CHANNEL, Logger.ERROR);
throw new SlideException(e.getMessage());
}
storesClass.put(storeName, storeClass);
// Load descriptor store parameters
Hashtable storeParameters = new Hashtable();
while (storeParametersDefinitions.hasMoreElements()) {
Configuration parameterDefinition = (Configuration)
storeParametersDefinitions.nextElement();
String parameterName = parameterDefinition.getAttribute("name");
String parameterValue = parameterDefinition.getValue();
storeParameters.put(parameterName, parameterValue);
}
storesParameters.put(storeName, storeParameters);
// Now reading the "child" stores
Hashtable currentStoreChildStores = new Hashtable();
// Loading node store (if any)
try {
Configuration nodeStoreDefinition =
storeDefinition.getConfiguration(NODE_STORE);
try {
Configuration referenceDefinition =
storeDefinition.getConfiguration(REFERENCE);
currentStoreChildStores.put
(NODE_STORE, referenceDefinition.getAttribute("store"));
getLogger().log("Node store references " + referenceDefinition.getAttribute("store"),LOG_CHANNEL,Logger.INFO);
} catch (ConfigurationException ex) {
getLogger().log("Node store: " + nodeStoreDefinition.getAttribute("classname"),LOG_CHANNEL,Logger.INFO);
NodeStore nodeStore =
(NodeStore) loadChildStore(nodeStoreDefinition,
storeParameters);
if (nodeStore != null) {
currentStoreChildStores.put(NODE_STORE, nodeStore);
}
}
} catch (Exception e) {
}
// Loading security store (if any)
try {
Configuration securityStoreDefinition =
storeDefinition.getConfiguration(SECURITY_STORE);
try {
Configuration referenceDefinition =
securityStoreDefinition.getConfiguration(REFERENCE);
currentStoreChildStores.put
(SECURITY_STORE,
referenceDefinition.getAttribute("store"));
getLogger().log("Security store references " + referenceDefinition.getAttribute("store"),LOG_CHANNEL,Logger.INFO);
} catch (ConfigurationException ex) {
getLogger().log("Security store: " + securityStoreDefinition.getAttribute("classname"),LOG_CHANNEL,Logger.INFO);
SecurityStore securityStore =
(SecurityStore) loadChildStore(securityStoreDefinition,
storeParameters);
if (securityStore != null) {
currentStoreChildStores.put(SECURITY_STORE, securityStore);
}
}
} catch (Exception e) {
}
// Loading lock store (if any)
try {
Configuration lockStoreDefinition =
storeDefinition.getConfiguration(LOCK_STORE);
try {
Configuration referenceDefinition =
lockStoreDefinition.getConfiguration(REFERENCE);
currentStoreChildStores.put
(LOCK_STORE, referenceDefinition.getAttribute("store"));
getLogger().log("Lock store store references " + referenceDefinition.getAttribute("store"),LOG_CHANNEL,Logger.INFO);
} catch (ConfigurationException ex) {
getLogger().log("Lock store store: " + lockStoreDefinition.getAttribute("classname"),LOG_CHANNEL,Logger.INFO);
LockStore lockStore =
(LockStore) loadChildStore(lockStoreDefinition,
storeParameters);
if (lockStore != null) {
currentStoreChildStores.put(LOCK_STORE, lockStore);
}
}
} catch (Exception e) {
}
// Loading revision descriptors store (if any)
try {
Configuration revisionDescriptorsStoreDefinition =
storeDefinition.getConfiguration
(REVISION_DESCRIPTORS_STORE);
try {
Configuration referenceDefinition =
revisionDescriptorsStoreDefinition
.getConfiguration(REFERENCE);
currentStoreChildStores.put
(REVISION_DESCRIPTORS_STORE,
referenceDefinition.getAttribute("store"));
getLogger().log("Revision descriptors store references " + referenceDefinition.getAttribute("store"),LOG_CHANNEL,Logger.INFO);
} catch (ConfigurationException ex) {
getLogger().log("Revision descriptors store: " + revisionDescriptorsStoreDefinition.getAttribute("classname"),LOG_CHANNEL,Logger.INFO);
RevisionDescriptorsStore revisionDescriptorsStore =
(RevisionDescriptorsStore) loadChildStore
(revisionDescriptorsStoreDefinition, storeParameters);
if (revisionDescriptorsStore != null) {
currentStoreChildStores.put(REVISION_DESCRIPTORS_STORE,
revisionDescriptorsStore);
}
}
} catch (Exception e) {
}
// Loading revision descriptor store (if any)
try {
Configuration revisionDescriptorStoreDefinition =
storeDefinition.getConfiguration(REVISION_DESCRIPTOR_STORE);
try {
Configuration referenceDefinition =
revisionDescriptorStoreDefinition
.getConfiguration(REFERENCE);
currentStoreChildStores.put
(REVISION_DESCRIPTOR_STORE,
referenceDefinition.getAttribute("store"));
getLogger().log("Revision descriptor store references " + referenceDefinition.getAttribute("store"),LOG_CHANNEL,Logger.INFO);
} catch (ConfigurationException ex) {
getLogger().log("Revision descriptor store: " + revisionDescriptorStoreDefinition.getAttribute("classname"),LOG_CHANNEL,Logger.INFO);
RevisionDescriptorStore revisionDescriptorStore =
(RevisionDescriptorStore) loadChildStore
(revisionDescriptorStoreDefinition, storeParameters);
if (revisionDescriptorStore != null) {
currentStoreChildStores.put(REVISION_DESCRIPTOR_STORE,
revisionDescriptorStore);
}
}
} catch (Exception e) {
}
// Loading content store (if any)
try {
Configuration contentStoreDefinition =
storeDefinition.getConfiguration(CONTENT_STORE);
try {
Configuration referenceDefinition =
contentStoreDefinition.getConfiguration(REFERENCE);
currentStoreChildStores.put
(CONTENT_STORE, referenceDefinition.getAttribute("store"));
getLogger().log("Content store references " + referenceDefinition.getAttribute("store"),LOG_CHANNEL,Logger.INFO);
} catch (ConfigurationException ex) {
getLogger().log("Content store: " + contentStoreDefinition.getAttribute("classname"),LOG_CHANNEL,Logger.INFO);
ContentStore contentStore =
(ContentStore) loadChildStore(contentStoreDefinition,
storeParameters);
if (contentStore != null) {
currentStoreChildStores.put(CONTENT_STORE, contentStore);
}
}
} catch (Exception e) {
}
childStores.put(storeName, currentStoreChildStores);
}
/**
* Load a child descriptors store.
*
* @param childStoreDefinition XML definition of the child store
* @param fatherParameters XML parameters defined for the father
* @return Service Instance of the child store
* @exception ConfigurationException Error parsing configuration file
* @exception SlideException Error loading the specified class
*/
private Service loadChildStore(Configuration childStoreDefinition,
Hashtable fatherParameters)
throws ConfigurationException, SlideException {
// Load classname
String childStoreClassname =
childStoreDefinition.getAttribute("classname");
// Load descriptors store class
Service childStore = null;
try {
Class childStoreClass =
Class.forName(childStoreClassname);
childStore = (Service) childStoreClass.newInstance();
} catch (Exception e) {
getLogger().log(e,LOG_CHANNEL, Logger.ERROR);
return null;
}
// Retrieve parent parameters
Hashtable childStoreParameters = new Hashtable();
Enumeration fatherParametersKeys = fatherParameters.keys();
while (fatherParametersKeys.hasMoreElements()) {
Object key = fatherParametersKeys.nextElement();
Object value = fatherParameters.get(key);
childStoreParameters.put(key, value);
}
// Load parameters
Enumeration childStoreParametersDefinitions =
childStoreDefinition.getConfigurations("parameter");
while (childStoreParametersDefinitions.hasMoreElements()) {
Configuration parameterDefinition = (Configuration)
childStoreParametersDefinitions.nextElement();
String parameterName = parameterDefinition.getAttribute("name");
String parameterValue = parameterDefinition.getValue();
childStoreParameters.put(parameterName, parameterValue);
}
childStore.setParameters(childStoreParameters);
return childStore;
}
/**
* Parse the content store definition.
*
* @param storesClass Class names of the descriptors stores
* @param storesParameters Parameters of the descriptors stores
* @param childStores Child stores instances
* @exception ConfigurationException Error parsing configuration file
* @exception UnknownServiceDeclarationException Reference to
* unknown service
* @exception ServiceParameterErrorException Service parameter error
* @exception ServiceParameterMissingException Service parameter missing
* @exception ServiceRegistrationFailedException Error registering service
*/
private void loadScopeDefinition(Configuration scopeDefinition,
Hashtable storesClass,
Hashtable storesParameters,
Hashtable childStores)
throws ConfigurationException, UnknownServiceDeclarationException,
ServiceParameterErrorException, ServiceParameterMissingException,
ServiceRegistrationFailedException {
String match = scopeDefinition.getAttribute("match");
// First, we get the correct class and parameters from the Hashtables.
String storeName = scopeDefinition.getAttribute("store");
if (storeName != null) {
if ((!storesClass.containsKey(storeName)) ||
(!storesParameters.containsKey(storeName))) {
throw new UnknownServiceDeclarationException(storeName);
}
registerStore(storeName,
(Class) storesClass.get(storeName),
(Hashtable) storesParameters.get(storeName),
new Scope(match),
(Hashtable) childStores.get(storeName));
getLogger().log("Registering Store "
+ storeName
+ " of class "
+ storesClass.get(storeName)
+ " with parameters "
+ storesParameters.get(storeName)
+ " on scope " + match,LOG_CHANNEL,Logger.INFO);
}
}
}