/*
* $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/common/Domain.java,v 1.42.2.3 2004/03/29 12:35:33 unico Exp $
* $Revision: 1.42.2.3 $
* $Date: 2004/03/29 12:35:33 $
*
* ====================================================================
*
* Copyright 1999-2002 The Apache Software Foundation
*
* Licensed 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.
*
*/
package org.apache.slide.common;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.slide.authenticate.SecurityToken;
import org.apache.slide.util.conf.Configuration;
import org.apache.slide.util.conf.ConfigurationElement;
import org.apache.slide.util.conf.ConfigurationException;
import org.apache.slide.util.conf.Populate;
import org.apache.slide.util.logger.Logger;
import org.xml.sax.InputSource;
/**
* The Domain controls access to its registered namespaces and performs
* initialization and connection management on behalf of the namespaces.
*
* <p>
* From the client application's perspective, the domain represents the only
* directly accessible object. It is through this object that the client
* gains access to namespaces, using the static method
* <code>Domain.accessNamespace()</code>.
* <p/>
* <p>
* Since the domain acts as the root of a directory service, it is a static
* entity and there can be only one domain per JVM.
* </p>
* <h3>Initialization</h3>
* <p>
* When Slide is first initialized, the Domain configuration is loaded.
* The location of the domain configuration file is given through the
* <code>org.apache.slide.domain</code> property in the Slide properties, or
* can be specified as argument to the static <code>Domain.init()</code>
* method.
* </p>
* <p>
* The domain configuration is written by an administrator and describes how
* each namespace is to be initialized. It includes information like:
* <ul>
* <li>
* The low-level services the namespace uses (structure store, content
* store, etc.)
* </li>
* <li>
* The namespace base topology, which includes the location of the base
* actions and paths in the namespace.
* </li>
* </ul>
* </p>
* <h3>Access and Security</h3>
* <p>
* After initialization is complete, the client application can request
* access to the domain. It uses one of the two methods:
* <ul>
* <li>
* {@link #accessNamespace Domain.accessNamespace(SecurityToken
securityObject, String namespace)}
* <br>
* Used to access a specific namespace. This method returns a
* <code>NamespaceAccessToken</code>, which thereafter must be used by
* the client application to perform operations on the namespace.
* <br><br>
* </li>
* <li>
* {@link #accessDomain Domain.accessDomain(SecurityToken
securityObject)}
* <br>
* Enumerates the registered namespaces with this domain. This allows
* application to browse the list of available namespaces.
* </li>
* </ul>
* </p>
* <p>
* The Domain uses an object (argument <code>securityObject</code>) to
* decide whether or not the client should be granted access. A good
* candidate is a reference to the client servlet or servlet context.<br><br>
* <i><small>Note: Currently, access control on namespaces is not
* implemented.</small></i>
* </p>
*
* @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
* @author Dirk Verbeeck
* @version $Revision: 1.42.2.3 $
*/
public final class Domain {
// -------------------------------------------------------------- Constants
private final static String LOG_CHANNEL = Domain.class.getName();
// ----------------------------------------------------- Instance Variables
/**
* Compatibility with the new embedded domain.
*/
private static EmbeddedDomain domain;
/**
* Namespaces hashtable.
*/
private static Hashtable namespaces;
private static boolean namespacesInitialized = false;
/**
* Active namespaces hashtable.
*/
private static Hashtable activeNamespaces;
/**
* Slide logger.
*/
private static Logger logger;
/**
* Default namespace.
*/
private static String defaultNamespace;
/**
* Domain parameters
*/
private static Hashtable parameters;
// --------------------------------------------------------- Public Methods
/**
* Tests if the domain has been initialized before.
*
* @return boolean True if the domain has already been initialized
*/
public static boolean isInitialized() {
return ((domain != null) || (namespaces != null));
}
/**
* Return true, if all namespaces have been initialized.
*/
public static boolean namespacesAreInitialized() {
return namespacesInitialized;
}
/**
* Set the domain as having been initialized before.
*/
public static void setInitialized(boolean initialized) {
if (initialized) {
if( namespaces == null ) namespaces = new Hashtable();
if( activeNamespaces == null ) activeNamespaces = new Hashtable();
if( parameters == null ) parameters = new Hashtable();
if (logger == null) {
logger = new org.apache.slide.util.logger.SimpleLogger();
logger.setLoggerLevel(Logger.INFO);
}
namespacesInitialized = true;
}
else {
// TODO: don't know what to do here ???
}
}
/**
* Return the default namespace of this domain.
*
* @return the name of the default namespace
*/
public static String getDefaultNamespace() {
if (!isInitialized())
selfInit();
if (domain != null)
return domain.getDefaultNamespace();
return defaultNamespace;
}
/**
* Access a Namespace.
*
* @param token Entity which wants access
* @param namespaceName Name of the namespace on which access is requested
* @return NamespaceAccessToken Access token to the namespace
*/
public static NamespaceAccessToken accessNamespace(SecurityToken token,
String namespaceName) {
if (!isInitialized())
selfInit();
if (domain != null)
return domain.getNamespaceToken(namespaceName);
Namespace namespace = (Namespace) namespaces.get(namespaceName);
if (namespace == null)
return null;
else
return new NamespaceAccessTokenImpl(namespace);
}
/**
* Enumerate namespace names.
*/
public static Enumeration enumerateNamespaces() {
if (!isInitialized())
return (new Vector()).elements();
if (domain != null)
return domain.enumerateNamespaces();
return (namespaces.keys());
}
/**
* Close a namespace.
*
* @param token Namespace access token
*/
public static void closeNamespace(NamespaceAccessToken token) {
token.disconnect();
activeNamespaces.remove(token.getName());
}
/**
* Clsose a namespace.
*
* @param token Entity which wants to close the namespace
* @param namespaceName Name of the namespace
*/
public static void closeNamespace(SecurityToken token,
String namespaceName) {
try {
Namespace namespace = (Namespace) namespaces.get(namespaceName);
namespace.disconnectServices();
activeNamespaces.remove(namespaceName);
} catch(Exception e) {
}
}
/**
* Access a Domain.
*
* @param token Service who wants access
* @return DomainAccessToken Access token to the domain
*/
public static DomainAccessToken accessDomain(SecurityToken token) {
// Not implemented
return null;
}
/**
* holds the expanded file name of domain.xml
**/
private static String domainFileName = "Domain.xml";
/**
* Access the file name of domain.xml.
*
* @return String the expanded file name as a string.
*/
public static String getDomainFileName() {
return domainFileName;
}
/**
* Domain initialization routine using Avalon configuration parser.
*
* @param configurationURL The file name to read the configuration
*/
public static void init(java.net.URL configurationURL) throws Exception {
if (isInitialized())
return;
domainFileName = configurationURL.getFile();
init(configurationURL.openStream());
}
/**
* Domain initialization routine using Avalon configuration parser.
*
* @param configurationFileName The file name to read the configuration
*/
public static void init(String configurationFileName) throws Exception {
if (isInitialized())
return;
domainFileName = configurationFileName;
init(new FileInputStream(configurationFileName));
}
/**
* Domain initialization routine using Avalon configuration parser.
*
* @param configurationInputStream The file name to read the configuration
*/
public static void init(InputStream configurationInputStream)
throws Exception {
if (isInitialized())
return;
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(false);
factory.setValidating(false);
SAXParser parser = factory.newSAXParser();
Populate pop = new Populate();
Configuration slideConfiguration =
new ConfigurationElement(pop.load(new InputSource
(configurationInputStream), parser.getXMLReader()));
Domain.init(slideConfiguration);
}
/**
* Domain initialization routine using Avalon configuration parser.
*
* @param configuration Avalon configuration object
*/
public static void init(Configuration configuration) {
if (isInitialized())
return;
parameters = new Hashtable();
defaultNamespace = configuration.getAttribute("default", "slide");
parameters.put( "default", defaultNamespace );
String loggerClass = configuration.getAttribute
("logger", "org.apache.slide.util.logger.SimpleLogger");
parameters.put("logger", loggerClass);
try {
logger = (Logger) (Class.forName(loggerClass).newInstance());
int loggerLevel = configuration.getAttributeAsInt("logger-level", Logger.INFO);
logger.setLoggerLevel(loggerLevel);
parameters.put("logger-level", "" + loggerLevel);
} catch (Exception e) {
if (logger == null) {
System.err.println("Slide domain: initialization of logger failed.");
e.printStackTrace();
} else {
error(e);
}
throw new DomainInitializationFailedError("Logger Problem: " + e.toString());
}
info("Initializing Domain");
namespaces = new Hashtable();
activeNamespaces = new Hashtable();
// Now initializing the domain
// Loading configuration
Properties properties =
org.apache.slide.util.Configuration.getDefault();
info("Domain configuration : " + properties.toString());
// Loading domain parameters
Enumeration parametersEnum =
configuration.getConfigurations("parameter");
while( parametersEnum.hasMoreElements() ) {
Configuration p = (Configuration)parametersEnum.nextElement();
parameters.put( p.getAttribute("name"), p.getValue() );
}
info( "Domain parameters: "+String.valueOf(parameters) );
// Loading namespaces
Enumeration namespaceDefinitions =
configuration.getConfigurations("namespace");
while (namespaceDefinitions.hasMoreElements()) {
initNamespace((Configuration) namespaceDefinitions.nextElement());
}
if (namespaces.isEmpty()) {
throw new DomainInitializationFailedError();
}
namespacesInitialized = true;
}
// --------------------------------------------------------- Logger Methods
/**
* Log.
*
* @param data The object to log.
* @param channel The channel name used for logging.
* @param level The level used for logging.
*/
public static void log(Object data, String channel, int level) {
logger.log(data, channel, level);
}
/**
* Log.
*
* @param data The object to log.
* @param level The level used for logging.
*/
public static void log(Object data, int level) {
logger.log(data,LOG_CHANNEL, level);
}
/**
* Log.
*
* @param data The object to log.
*/
public static void log(Object data) {
logger.log(data,LOG_CHANNEL,Logger.DEBUG);
}
/**
* Debug.
*
* @param data The object to log
*/
public static void debug(Object data) {
log(data,LOG_CHANNEL, Logger.DEBUG);
}
/**
* Error.
*
* @param data The object to log
*/
public static void error(Object data) {
log(data,LOG_CHANNEL, Logger.ERROR);
}
/**
* Error.
*
* @param data The object to log
* @param t Throwable object
*/
public static void error(Object data, Throwable t) {
log(data + " - " + t.getMessage(),LOG_CHANNEL, Logger.ERROR);
log(t,LOG_CHANNEL, Logger.ERROR);
}
/**
* Info.
*
* @param data The object to log
*/
public static void info(Object data) {
log(data,LOG_CHANNEL, Logger.INFO);
}
/**
* Warning.
*
* @param data The object to log
*/
public static void warn(Object data) {
log(data,LOG_CHANNEL, Logger.WARNING);
}
/**
* Check if the channel with the specified level is enabled for logging.
* This implementation ignores the channel specification
*
* @param channel The channel specification
* @param level The level specification
*/
public static boolean isEnabled(String channel, int level) {
return logger.isEnabled(channel, level);
}
/**
* Check if the default channel with the specified level is enabled for
* logging.
*
* @param level The level specification
*/
public static boolean isEnabled(int level) {
return logger.isEnabled(LOG_CHANNEL,level);
}
/**
* Check if the default channel with the DEBUG level is enabled for
* logging.
*/
public static boolean isDebugEnabled() {
return isEnabled(LOG_CHANNEL,Logger.DEBUG);
}
/**
* Check if the default channel with the WARNING level is enabled for
* logging.
*/
public static boolean isWarningEnabled() {
return isEnabled(LOG_CHANNEL,Logger.WARNING);
}
/**
* Check if the default channel with the INFO level is enabled for logging.
*/
public static boolean isInfoEnabled() {
return isEnabled(LOG_CHANNEL,Logger.INFO);
}
/**
* Check if the default channel with the ERROR level is enabled for
* logging.
*/
public static boolean isErrorEnabled() {
return isEnabled(LOG_CHANNEL,Logger.ERROR);
}
// -------------------------------------------------------- Package Methods
/**
* Set the embedded domain field.
*/
static void setDomain(EmbeddedDomain domain) {
Domain.domain = domain;
}
/**
* Start domain (doesn't do anything yet).
*/
static void start()
throws Exception {
}
/**
* Stop domain.
*/
static void stop()
throws Exception {
Enumeration active = activeNamespaces.elements();
while (active.hasMoreElements()) {
((Namespace) active.nextElement()).disconnectServices();
}
}
/**
* Add a namespace to the domain.
*
* @param namespace Namespace to be added
*/
static void addNamespace(Namespace namespace) {
namespaces.put(namespace.getName(), namespace);
activeNamespaces.put(namespace.getName(), namespace);
}
/**
* Get a namespace.
*
* @param namespaceName Name of the namespace
* @return Namespace
*/
static Namespace getNamespace(String namespaceName) {
return (Namespace) namespaces.get(namespaceName);
}
/**
* Get a domain parameter.
* @param name the parameter name
* @return the parameter value
*/
public static String getParameter( String name ) {
return (String)parameters.get( name );
}
/**
* Get a domain parameter.
* @param name the parameter name
* @param defaultValue the default value to be returned
* @return the parameter value
*/
public static String getParameter( String name, String defaultValue ) {
String result = (String)parameters.get( name );
if( result == null )
result = defaultValue;
return result;
}
/**
* Set the specified parameters
*
* @param parameters the parameters
*
*/
static void setParameters( Hashtable parameters ) {
Domain.parameters = parameters;
}
/**
* Set the logger to be used by Slide.
*
* @param logger Logger the domain will use
*/
static void setLogger(Logger logger) {
Domain.logger = logger;
}
/**
* Get the Domain logger.
*
* @return The domain logger
*/
static Logger getLogger() {
return Domain.logger;
}
/**
* Default initialization of the domain.
*/
static void selfInit() {
String loggerClass = "org.apache.slide.util.logger.SimpleLogger";
if (logger == null) {
try {
logger = (Logger)(Class.forName(loggerClass).newInstance());
logger.setLoggerLevel(Logger.INFO);
}
catch (Exception e) {
error(e);
throw new DomainInitializationFailedError
("Logger Problem: " + e.toString());
}
}
info("Auto-Initializing Domain");
// Now initializing the domain
// Loading configuration
Properties configuration =
org.apache.slide.util.Configuration.getDefault();
info("Domain configuration : " + configuration.toString());
// First, retrieve the domain XML definition file from
// the configuration
String fileName =
org.apache.slide.util.Configuration.getDefault().getProperty
(org.apache.slide.util.Configuration.Property.DomainInitFilename,
"Domain.xml");
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(false);
factory.setValidating(false);
SAXParser parser = factory.newSAXParser();
FileInputStream is = new FileInputStream(fileName);
//init(reader);
Populate pop = new Populate();
Configuration slideConfiguration =
new ConfigurationElement(pop.load(new InputSource(is),
parser.getXMLReader()));
init(slideConfiguration);
} catch (javax.xml.parsers.FactoryConfigurationError e) {
throw new DomainInitializationFailedError(e.getMessage());
} catch (Exception e) {
throw new DomainInitializationFailedError(e.getMessage());
}
info("Domain initialization complete");
}
// -------------------------------------------------------- Private Methods
/**
* Initializes a new namespace based on the given configuration data.
*
* @param configuration Configuration object
*/
private static void initNamespace(Configuration configuration) {
try {
try {
info("Initializing namespace : "
+ configuration.getAttribute("name"));
} catch (ConfigurationException e) {
error(e);
}
String loggerClass = configuration.getAttribute
("logger", null);
Logger namespaceLogger = null;
if (loggerClass==null) {
// if there is no logger defined on the namespace
// use the domain logger
namespaceLogger=logger;
}
else {
try {
namespaceLogger =
(Logger) (Class.forName(loggerClass).newInstance());
namespaceLogger.setLoggerLevel(configuration.getAttributeAsInt
("logger-level", Logger.INFO));
} catch (Exception e) {
error(e);
}
}
Namespace namespace = new Namespace();
namespace.setName(configuration.getAttribute("name"));
namespace.setLogger(namespaceLogger);
Configuration namespaceConfigurationDefinition =
configuration.getConfiguration("configuration");
namespace.loadParameters(namespaceConfigurationDefinition);
Configuration namespaceDefinition =
configuration.getConfiguration("definition");
namespace.loadDefinition(namespaceDefinition);
addNamespace(namespace);
try {
Configuration namespaceBaseDataDefinition =
configuration.getConfiguration("data");
namespace.loadBaseData(namespaceBaseDataDefinition);
} catch (ConfigurationException e) {
info("No basedata found for the namespace");
}
namespace.loadConfiguration(namespaceConfigurationDefinition);
// preparation to add services, please ignore now
try {
Configuration services = configuration.getConfiguration("services");
Enumeration s = services.getConfigurations("service");
while (s.hasMoreElements()) {
Configuration service = (Configuration)s.nextElement();
System.out.println("&&&&&&Name = " + service.getName());
System.out.println("&&&&&&className = " + service.getAttribute("classname"));
System.out.println("&&&&&&serviceName = " + service.getAttribute("name"));
Enumeration s_pars = service.getConfigurations("parameter");
while (s_pars.hasMoreElements()) {
Configuration s_par = (Configuration)s_pars.nextElement();
System.out.println("&&&&&&PAR Name = " + s_par.getName());
System.out.println("&&&&&&PAR Name = " + s_par.getAttribute("name"));
System.out.println("&&&&&&Par Val = " + s_par.getValue());
}
}
}
catch (ConfigurationException e){
// silently ignore it ==> no services
}
catch (Exception e){
error(e);
}
// preparation to add services, please ignore now
info("Namespace configuration complete");
} catch (Throwable t) {
error(t);
}
}
}