CCM NG: Current status

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@3498 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2015-06-24 15:43:14 +00:00
parent 7f2da80e81
commit 9a2c98cbe0
70 changed files with 9154 additions and 68 deletions

View File

@ -48,6 +48,30 @@
<artifactId>hibernate-validator</artifactId> <artifactId>hibernate-validator</artifactId>
</dependency> </dependency>
<!-- Dependencies for log4j 2 including adapter for the log4j 1.2 API -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<dependency>
<groupId>oro</groupId>
<artifactId>oro</artifactId>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>

View File

@ -0,0 +1,203 @@
/*
* Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.kernel;
import com.arsdigita.runtime.AbstractConfig;
import com.arsdigita.util.parameter.BooleanParameter;
import com.arsdigita.util.parameter.EnumerationParameter;
import com.arsdigita.util.parameter.Parameter;
import com.arsdigita.util.parameter.StringParameter;
import java.util.StringTokenizer;
import org.apache.log4j.Logger;
/**
* @author Justin Ross
* @see com.arsdigita.kernel.Kernel
* @version $Id$
*/
public final class KernelConfig extends AbstractConfig {
/** A logger instance. */
private static final Logger s_log = Logger.getLogger(KernelConfig.class);
/** Singelton config object. */
private static KernelConfig s_conf;
/**
* Gain a KernelConfig object.
*
* Singelton pattern, don't instantiate a KernelConfig object using the
* constructor directly!
* @return
*/
public static synchronized KernelConfig getConfig() {
if (s_conf == null) {
s_conf = new KernelConfig();
s_conf.load();
}
return s_conf;
}
/** TODO: should be renamed waf.kernel.debug" */
private static Parameter m_debug = new BooleanParameter
("waf.debug", Parameter.REQUIRED, Boolean.FALSE);
/** Whether WEB development support should be activated (true) or not. */
// Handled in OLD initializer c.ad.webdevsupport.LegacyInitializer
private static Parameter m_webdevSupport = new BooleanParameter
("waf.webdev_support", Parameter.REQUIRED, Boolean.FALSE);
private final Parameter m_permissions = new BooleanParameter
("waf.kernel.data_permission_check_enabled", Parameter.REQUIRED,
Boolean.TRUE);
/** User Login by screen name or email address */
private final EnumerationParameter m_identifier = new EnumerationParameter
("waf.kernel.primary_user_identifier", Parameter.REQUIRED,
"email");
/**
* */
private final Parameter m_SSO = new BooleanParameter
("waf.kernel.sso_login", Parameter.REQUIRED, Boolean.FALSE);
/**
* */
private final Parameter m_remember = new BooleanParameter
("waf.kernel.remember_login", Parameter.REQUIRED, Boolean.TRUE);
/**
* */
private final Parameter m_secureLogin = new BooleanParameter
("waf.kernel.secure_login", Parameter.REQUIRED, Boolean.FALSE);
/** String containing the supported languages.
The first one is considered default. */
private final Parameter m_supportedLanguages = new StringParameter
("waf.kernel.supported_languages", Parameter.REQUIRED,
"en,de,fr,nl,it,pt,es");
private final Parameter m_languageIndependentItems = new BooleanParameter
("waf.kernel.language_independent_items", Parameter.REQUIRED, Boolean.FALSE);
private final Parameter m_languageIndependentCode = new StringParameter
("waf.kernel.language_independent_code", Parameter.OPTIONAL,
"--");
/**
* Constructor
*/
public KernelConfig() {
// Add recognised Login user identification to enumeration parameter
m_identifier.put("email", "email");
m_identifier.put("screen_name", "screenName");
register(m_debug);
register(m_webdevSupport);
register(m_permissions);
register(m_identifier);
register(m_SSO);
register(m_remember);
register(m_secureLogin);
register(m_supportedLanguages);
register(m_languageIndependentItems);
register(m_languageIndependentCode);
loadInfo();
}
public final boolean isDebugEnabled() {
return ((Boolean) get(m_debug)).booleanValue();
}
/**
* Return true, if WEB developer support should be activated.
*/
public final boolean isWebdevSupportActive() {
return ((Boolean) get(m_webdevSupport)).booleanValue();
}
public final boolean isDataPermissionCheckEnabled() {
return ((Boolean) get(m_permissions)).booleanValue();
}
public final String getPrimaryUserIdentifier() {
return (String) get(m_identifier);
}
public final boolean emailIsPrimaryIdentifier() {
return "email".equals(get(m_identifier));
}
public final boolean screenNameIsPrimaryIdentifier() {
return !emailIsPrimaryIdentifier();
}
public final boolean isSSOenabled() {
return ((Boolean) get(m_SSO)).booleanValue();
}
// XXX Move this to WebConfig.
public final boolean isLoginRemembered() {
return ((Boolean) get(m_remember)).booleanValue();
}
public final boolean isSecureLoginRequired() {
return ((Boolean) get(m_secureLogin)).booleanValue();
}
/**
* Returns the defaultLanguage flag.
*/
public final String getDefaultLanguage() {
return ((String) get(m_supportedLanguages)).trim().substring(0, 2);
}
/**
* Returns the supportedLanguages as String.
*/
public final String getSupportedLanguages() {
return (String) get(m_supportedLanguages);
}
/**
* Returns the supportedLanguages as StringTokenizer.
*/
public final StringTokenizer getSupportedLanguagesTokenizer() {
return new StringTokenizer(this.getSupportedLanguages(), ",", false);
}
/**
* Returns the languagesIndependentCode as String.
*/
public final String getLanguagesIndependentCode() {
return (String) get(m_languageIndependentCode);
}
/**
* Return true, if language lang is part of supported langs
*/
public final boolean hasLanguage(String lang) {
return ((String) get(m_supportedLanguages)).contains(lang);
}
public final boolean languageIndependentItems() {
return ((Boolean) get(m_languageIndependentItems)).booleanValue();
}
}

View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.runtime;
import com.arsdigita.util.parameter.AbstractParameterContext;
import com.arsdigita.util.parameter.ErrorList;
import org.apache.log4j.Logger;
/**
* AbstractConfig is a base class for groups of customizable
* configuration {@link com.arsdigita.util.parameter parameters}. A
* CCM Developer wishing to add a new group of configuration
* parameters to his application will extend this class and provide a
* public noargs constructer that registers his parameters with the
* superclass. For example:
*
* <blockquote><pre>
* package com.arsdigita.exampleApp;
*
* public final class ExampleConfig extends AbstractConfig {
*
* private Parameter m_string = new StringParameter
* ("example.string", Parameter.OPTIONAL, "default");
* private Parameter m_integer = new IntegerParameter
* ("example.integer", Parameter.OPTIONAL, new Integer(0));
* private Parameter m_boolean = new BooleanParameter
* ("example.boolean", Parameter.OPTIONAL, Boolean.TRUE);
*
* public ExampleConfig() {
* register(m_string);
* register(m_integer);
* register(m_boolean);
* loadInfo();
* }
*
* public String getString() {
* return (String) get(m_string);
* }
*
* public int getInteger() {
* return ((Integer) get(m_integer)).intValue();
* }
*
* public boolean getBoolean() {
* return Boolean.TRUE.equals(get(m_boolean));
* }
*
* }
* </pre></blockquote>
*
* When this pattern is followed, the resulting subclass of abstract
* config may be used by developers writing java code to access the
* values of customizable configuration parameters in a convenient and
* type safe manner. In addition, the very same class is also usable
* by the ccm configuration tools to allow customization and
* validation of the new parameters.
*
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public abstract class AbstractConfig extends AbstractParameterContext {
private static final Logger s_log = Logger.getLogger
(AbstractConfig.class);
/**
* Default constructor for subclasses.
*/
protected AbstractConfig() {}
/**
* Loads this AbstractConfig object with values from the default
* configuration registry. Any errors encountered during
* unmarshaling and loading of configuration values are added to
* the <code>errors</code> ErrorList. This method should not be
* called from the constructor of a config object since the ccm
* configuration tools need to be able to construct empty config
* objects.
*
* @param errors The ErrorList used to record errors during
* unmarshaling and loading.
*
* @see ConfigRegistry
*/
public final void load(ErrorList errors) {
ConfigRegistry reg = new ConfigRegistry();
reg.load(this, errors);
}
/**
* Invokes the {@link #load(ErrorList)} method with a new and
* empty ErrorList for accumulating errors, and returns that
* ErrorList. This method can be used in combination with the
* {@link ErrorList#check()} method to load and assert that this
* configuration object is valid in one simple idiom. For example:
*
* <blockquote><pre>
* ExampleConfig conf = new ExampleConfig();
* conf.load().check();
* ...
* </pre></blockquote>
*
* @return Errors that may have been encountered during
* configuration loading.
*
* @see #load(ErrorList)
*/
public final ErrorList load() {
ErrorList errs = new ErrorList();
load(errs);
return errs;
}
/**
* @deprecated Use @{link #load()} instead.
*/
public final ErrorList load(final String resource) {
return load();
}
/**
* @deprecated Use @{link #load()} instead.
*/
public final ErrorList require(final String resource) {
return load();
}
}

View File

@ -0,0 +1,365 @@
/*
* Copyright (C) 2004 Red Hat Inc. All Rights Reserved.
* Copyright (C) 2009 Peter Boy (pb@zes.uni-bremen.de) All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.runtime;
import com.arsdigita.util.UncheckedWrapperException;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.log4j.Logger;
/**
* <p>CCMResourceManager Runtime environment repository object, stores essential
* properties of the runtime environment and provides them on request.</p>
*
* <p>Currently, is is limited to the </p>
* <ul>
* <li>base directory of the running webapp</li>
* </ul>
* <p>It provides public methods to make the properties available.</p>
*
* <p>The singleton is initialised</p>
* <ul>
* <li>either during startup of the container (called by
* @see com.arsdigita.web.CCMApplicationContextListener (must be configured in
* web.xml)</li>
* <li>or by the command line system at the beginning of the processing (esp.
* package @see com.arsdigita.packaging.Mastertool).</li>
* </ul>
* <p>Currently as a fall back mechanism the environmant Variable CCM_HOME is
* evaluated and used a last resort, if no initialisation has been done when
* a getter is first called.</p>
*
* <p>It is essential for the proper working of CCM that CCMResourceManager is
* initialised before any operation starts, as it is the case with the Startup
* class of the runtime package, which is responsible for organising database
* access.</p>
*
*
* <p><b>Subject to change!</b></p>
*
* A similiar task is performed by com.arsdigita.util.ResourceManager
*
* @author Justin Ross &lt;jross@redhat.com&gt;
* rewritten by
* @author pboy &lt;pboy@barkhof.uni-bremen.de&gt;
* @version $Id$
*/
public final class CCMResourceManager {
private static final Logger s_log = Logger.getLogger(CCMResourceManager.class);
private static CCMResourceManager s_ccm;
/**
* Full Pathname of the application base directory
* (document root in apache terminology)
*/
private static File m_baseDir;
/**
* Location of the registry in the applications directory tree
* as offset from the base directory
*/
// currently not used, should be refactored as File object for the sake of
// operating system independency!
// public static final String registryPath = "/WEB-INF/conf/registry";
// public static final File registryPath = null; // currently not used, work in progress
/* ************ Section singleton handlers ***************** */
/**
* Sets the singleton configuration property for the runtime
* environment.
*
*/
public static final synchronized void setBaseDirectory(String baseDirName) {
if (s_ccm == null) {
s_ccm = new CCMResourceManager();
s_ccm.storeBaseDir(baseDirName);
}
else {
// baseDir already set, silently discard
s_log.info("baseDir already set as " + m_baseDir + ". Discarded.");
}
}
/**
* Returns the singleton configuration property for the runtime
* environment.
*
* @return The <code>RuntimeConfig</code> record; it cannot be null
*/
public static final synchronized File getBaseDirectory() {
if (s_ccm == null) {
// should never happen, setBaseDirectory has to be executed first
// we try to resolve the problem in fetchBaseDir by search for
// a runtime environment variable (the old way).
s_ccm = new CCMResourceManager();
}
return s_ccm.fetchBaseDir();
}
/* ************ Section singleton handlers END ************** */
/* ************ Constructors Section ************** */
/**
* Following the singleton pattern: Private constructor to prevent other
* clients from instantiating the class (and the compiler from generating
* a default public constructor).
*/
private CCMResourceManager() { }
/* ************ Constructors Section END ************** */
/* ************ Public getter/setter Section *************** */
/**
* Retrieve the homeDir as URL.
*
* Note! API changed. @see getHomeDirectory()
* <b>May be removed in the future!</b>
*
* @return Directory location in the servers file system as URL object.
*/
public static final URL getHomeURL() {
try {
return CCMResourceManager.getHomeDirectory().toURL();
} catch (MalformedURLException e) {
throw new UncheckedWrapperException(e);
}
}
/**
* Retrieve the homeDir, which is the location of the servlet server's
* servlet container directory in the file system of the server machine,
* as File object.
*
* <b>Note! API changed!</b>
*
* Originally it is used to determine all file object locations of a
* CCM installation, during the installation step as well as
* while running the application inside a servlet container. The CCM installation
* of a servlet container used to use a non-standard layout. It is based upon a
* system wide environment variable CCM_HOME to determine the home directory.
*
* The dependency from a system wide environment variable prevents a servlet
* container to run multiple instances of CCM. In addition to it CCM will
* be migrated to be installable in a standard way to a standard container.
* Therefore all file locations will be given relative to the applications
* directory (the baseDirectory @see m_baseDir).
*
*
* Method getHomeDirectory() is preserved during the transition phase.
* <b>It may be removed in the future!</b> Or it may be moved to
* c.ad.packaging for assistence of the installation step only.
*
* MODIFIED:
* CCM_HOME is now interpreted as the path to the applications base
* directory (web application context).
*
* @return Directory location in the servers file system as File object.
*/
static final File getHomeDirectory() {
String home = System.getProperty("ccm.home");
if (home == null) {
throw new IllegalStateException
("The ccm.home system property is null or not defined");
}
// make a guess, wether it is old style (i.e. referring to the containers
// base directory and therefor does not contain the webapps part) or
// new style referring to the apps base directory (and therefor containing
// the webapps part)
if (home.indexOf("webapps") > 0 ){
// should be new style
}
else {
// presumably old style, add path to standard context name
home += "/webapps/ROOT";
}
File file = new File(home);
// No need to require that home exists (indeed, during install it will not).
// Should be created by invoking method if not.
// if (!file.exists()) {
// throw new IllegalStateException
// ("The file given in the ccm.home system property " +
// "does not exist");
// }
if (!file.isDirectory()) {
throw new IllegalStateException
("The file: " + home + " given in the ccm.home system property"
+ " is not a directory");
}
return file;
}
/**
* Provide the configDirectory as URL.
*
* @see getConfigDirectory() for details.
*
* <b>Note! API changed!</b>
*
* @return Directory location in the servers file system as URL object.
*/
public static final URL getConfigURL() {
try {
return CCMResourceManager.getConfigDirectory().toURL();
} catch (MalformedURLException e) {
throw new UncheckedWrapperException(e);
}
}
/**
* Retrieve the configDir, which is the location of the configuration
* database root (registry) in the file system tree of the server machine,
* as File object.
*
* @return Directory location in the servers file system as File object.
*/
public static final File getConfigDirectory() {
// Keep this in sync with informational attribut @see registryPath !
File confdir = new File(new File(new File(CCMResourceManager.getBaseDirectory(),
"WEB-INF"),"conf"), "registry");
if (!confdir.exists()) {
if (!confdir.mkdirs()) {
throw new IllegalStateException
("Could not create configuration directory: " + confdir);
}
}
if (!confdir.isDirectory()) {
throw new IllegalStateException
("Configuration directory value is not a directory: " + confdir);
}
return confdir;
}
/**
* getWorkDirectory retrieves and eventually creates an internal directory
* in the servlet container for temporary files (work files), where subsystems
* may create subdirectories for internal use (e.g. Lucene search enginge or
* the PublishToFile machinery).
*
* The containers work file directory could be used as well, but may be
* inappropriate in case of confidential data.
*
* @return Directory location in the servers file system as File object.
*/
public static final File getWorkDirectory() {
File file = new File(new File(CCMResourceManager.getBaseDirectory(),
"WEB-INF"),"work");
if (!file.exists()) {
if (!file.mkdirs()) {
throw new IllegalStateException
("Could not create work directory: " + file);
}
}
if (!file.isDirectory()) {
throw new IllegalStateException
("Work directory value is not a directory: " + file);
}
return file;
}
/* ************ Public getter/setter Section END *************** */
/* ************ Private Worker Section *************** */
/**
* Stores the passed in String as File object.
*
* @param baseDirName String containing the path, must not be null
*/
private final void storeBaseDir(String baseDirName) {
s_log.debug("storeBaseDir: BaseDir name is given as " + baseDirName );
m_baseDir = new File(baseDirName);
// eventually: check if dir exists, create it if not.
if (!m_baseDir.exists()) {
if (!m_baseDir.mkdirs()) {
throw new IllegalStateException
("Could not create base directory: " + m_baseDir);
}
}
if (!m_baseDir.isDirectory()) {
throw new IllegalStateException
("Base directory value is not a directory: " + m_baseDir);
}
}
/**
* Retrieves the stored BaseDir File object.
*
* @return Base directory location in the servers file system as File object.
*/
private final File fetchBaseDir() {
if (m_baseDir == null) {
// should never happen, but we try to cope with it anyway by
// falling back to getHomeDirectory() and the system wide
// environment variable.
// During transition phase only! Must be removed when the new
// standard compliant installation method is fully in place
// MODIFIED
// HomeDirectory now specifies the applications context dir.
m_baseDir = CCMResourceManager.getHomeDirectory();
// eventually: check if dir exists, create it if not.
if (!m_baseDir.exists()) {
if (!m_baseDir.mkdirs()) {
throw new IllegalStateException
("Could not create base directory: " + m_baseDir);
}
}
if (!m_baseDir.isDirectory()) {
throw new IllegalStateException
("Base directory value is not a directory: " + m_baseDir);
}
}
return m_baseDir;
}
/* ************ Private Worker Section END *************** */
}

View File

@ -0,0 +1,348 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.runtime;
import com.arsdigita.util.Classes;
import com.arsdigita.util.JavaPropertyReader;
import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.util.parameter.ErrorList;
import com.arsdigita.util.parameter.ParameterContext;
import com.arsdigita.util.parameter.ParameterReader;
import com.arsdigita.xml.XML;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.log4j.Logger;
/**
* The ConfigRegistry class maps between config classes (subclasses of
* {@link com.arsdigita.runtime.AbstractConfig}), and a location used
* for persisting the values in a config class.
*
* The ConfigRegistry also stores the set of configured packages for a
* particular CCMResourceManager instance.
* Additionally it stores a list of URLs for parent configurations that are
* used for defaulting values not present in the local configuration.
* This mapping is maintained and extended by CCMResourceManager developers through
* the use of an XML configuration file placed in the src tree for a
* particular package. If a particular package is configured, the
* ConfigRegistry class will look in the classpath for a registry
* configuration file named <i>package-key</i>.config, and parse the
* file according to the following specification:
*
* <blockquite><pre>
* &lt;?xml version="1.0" encoding="utf-8"?&gt;
* &lt;registry&gt;
* ...
* &lt;config class="CLASSNAME"
* storage="FILENAME"/&gt;
* ...
* &lt;/registry&gt;
* </pre></blockquite>
*
* The mappings stored by this ConfigRegistry will then be extended to include
* the classes and storage locations specified in the configuration file. These
* mappings are then used by the ConfigRegistry instance to load config objects.
*
* @author Rafael H. Schloming &lt;rhs@mit.edu&gt;
* @version $Revision$ $Date$
* @version $Id$
**/
public class ConfigRegistry {
private static final Logger s_log = Logger.getLogger(ConfigRegistry.class);
/**
* Base url for registry location(s).
* (i.e. $CATALINA_HOME/webapps/$context/WEB-INF/conf/registry in a
* standard installation)
*/
private URL m_url;
private ClassLoader m_loader;
private List m_packages = new ArrayList();
private List m_contexts = new ArrayList();
private Map m_storage = new HashMap();
private List m_loaders = new ArrayList();
/**
* Constructs a new config registry that will resolve all
* locations relative to <code>url</code>, and use
* <code>loader</code> when searching the classpath for registry
* configuration files.
*
* @param url The base url for registry locations.
* @param loader The ClassLoader to use for retrieving registry
* configuration files.
**/
public ConfigRegistry(URL url, ClassLoader loader) {
m_url = url;
m_loader = loader;
addContext(RegistryConfig.class, "registry.properties");
initialize(m_url, new ErrorList());
}
/**
* Convenience class which invokes {@link #ConfigRegistry(URL, ClassLoader)}
* defaulting the loader to the current context class loader.
*
* @see Thread#getContextClassLoader()
*
* @param url The base url for registry locations.
*/
public ConfigRegistry(URL url) {
this(url, Thread.currentThread().getContextClassLoader());
}
/**
* Convenience class which invokes {@link #ConfigRegistry(URL, ClassLoader)}
* defaulting the URL to
* <code>new File(System.getProperty("ccm.conf")).toURL()</code>. The value
* of the ccm.conf system property may or may not include a trailing slash.
*
* @param loader The ClassLoader to use when searching for
* registry configuration files.
*/
public ConfigRegistry(ClassLoader loader) {
this(CCMResourceManager.getConfigURL(), loader);
}
/**
* Invokes {@link #ConfigRegistry(URL)} defaulting the URL to <code>new
* File(System.getProperty("ccm.conf")).toURL()</code>. The value of the
* ccm.conf system property may or may not include a trailing slash.
*/
public ConfigRegistry() {
this(CCMResourceManager.getConfigURL());
}
/**
*
* @param url Base url for registry location(s).
* @param errs Errorlist
*/
private void initialize(URL url, ErrorList errs) {
ClassLoader ldr = new URLClassLoader(new URL[]{url}, null);
RegistryConfig rc = new RegistryConfig();
load(rc, errs, ldr);
String[] packages = rc.getPackages();
URL[] parents = rc.getParents();
for (int i = 0; i < packages.length; i++) {
if (!m_packages.contains(packages[i])) {
initialize(packages[i]);
}
}
for (int i = parents.length - 1; i >= 0; i--) {
initialize(parents[i], errs);
}
m_loaders.add(ldr);
}
/**
* This method is <strong>not</strong> supported API.
*/
public final void initialize(String key) {
s_log.debug(String.format("Initalizing for key '%s'", key));
if (m_packages.contains(key)) {
throw new IllegalArgumentException("already loaded: " + key);
}
InputStream is = m_loader.getResourceAsStream(key + ".config");
if (is != null) {
try {
XML.parse(is, new ConfigRegistryParser());
m_packages.add(key);
} finally {
try {
is.close();
} catch (IOException e) {
throw new UncheckedWrapperException(e);
}
}
}
}
/**
* Returns the list of configured packages for this ConfigRegistry.
*
* @return A list of package keys represented as Strings.
**/
public List getPackages() {
return m_packages;
}
/**
* Returns a list of config classes for this ConfigRegistry.
*
* @return A list of Class objects.
**/
public List getContexts() {
return m_contexts;
}
/**
* Returns the relative location used to store values for the
* given config class.
*
* @param context a subclass of {@link
* com.arsdigita.runtime.AbstractConfig}
*
* @return the relative storage location for <code>context</code>
*
* @throws IllegalArgumentException if this ConfigRegistry does
* not contain a mapping for <code>context</code>
**/
public String getStorage(Class context) {
if (!m_contexts.contains(context)) {
throw new IllegalArgumentException("no such context: " + context
+ "; available contexts="
+ m_contexts
+ "; context->storage map: "
+ m_storage);
}
return (String) m_storage.get(context);
}
private void addContext(Class context, String storage) {
s_log.debug(String.format("Adding context '%s', storage '%s'...",
context.getName(), storage));
m_contexts.add(context);
m_storage.put(context, storage);
}
/**
* Returns true if this ConfigRegistry contains a mapping for
* <code>context</code>
*
* @param context a subclass of {@link
* com.arsdigita.runtime.AbstractConfig}
*
* @return true if this ConfigRegistry contains a mapping for
* <code>context</code>
**/
public boolean isConfigured(Class context) {
return m_contexts.contains(context);
}
/**
* Loads the given config object from the correct location based
* on its class. Defaults all values based on the value of the
* <code>waf.config.parents</code> parameter. Any errors
* encountered during loading are reported in the given ErrorList.
*
* @param ctx the config object to load
* @param errs used to accumulate errors during loading
*
* @throws IllegalArgumentException if this ConfigRegistry does
* not contain a mapping for <code>ctx.getClass()</code>
**/
public void load(ParameterContext ctx, ErrorList errs) {
for (Iterator it = m_loaders.iterator(); it.hasNext();) {
ClassLoader ldr = (ClassLoader) it.next();
load(ctx, errs, ldr);
}
}
/**
* Searches through this ConfigRegistry and its parents for the
* given resource. If it is not found it is also searched for in
* the classpath specified by the loader passed to this
* ConfigRegistry on construction. This may be used to load
* configuration information that is not stored in a config
* object.
*
* @param resource the path to the resource
*
* @return an input stream containing the contents of the resource
* or null if the resource is not found
*/
public InputStream load(String resource) {
for (int i = m_loaders.size() - 1; i >= 0; i--) {
ClassLoader ldr = (ClassLoader) m_loaders.get(i);
InputStream is = ldr.getResourceAsStream(resource);
if (is != null) {
return is;
}
}
return m_loader.getResourceAsStream(resource);
}
private void load(ParameterContext ctx, ErrorList errs, ClassLoader ldr) {
Properties props = getProperties(ldr, getStorage(ctx.getClass()));
ParameterReader reader = new JavaPropertyReader(props);
ctx.load(reader, errs);
}
private Properties getProperties(ClassLoader ldr, String resource) {
Properties props = new Properties();
InputStream is = ldr.getResourceAsStream(resource);
if (is != null) {
try {
props.load(is);
} catch (IOException e) {
throw new UncheckedWrapperException(e);
} finally {
try {
is.close();
} catch (IOException e) {
throw new UncheckedWrapperException(e);
}
}
}
return props;
}
private class ConfigRegistryParser extends DefaultHandler {
@Override
public void startElement(String uri, String localName, String qn,
Attributes attrs) {
if (localName.equals("config")) {
String klass = attrs.getValue(uri, "class");
String storage = attrs.getValue(uri, "storage");
// XXX: Is there a better way to handle errors that
// includes line number information?
if ((klass == null) || (storage == null)) {
throw new IllegalArgumentException(
"class and storage attributes are required");
}
Class context = Classes.loadClass(klass);
addContext(context, storage);
}
}
}
}

View File

@ -0,0 +1,140 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.runtime;
// import com.arsdigita.runtime.AbstractConfig;
import com.arsdigita.util.StringUtils;
import com.arsdigita.util.parameter.ErrorList;
import com.arsdigita.util.parameter.Parameter;
import com.arsdigita.util.parameter.ParameterError;
import com.arsdigita.util.parameter.StringParameter;
import java.net.MalformedURLException;
import java.net.URL;
/**
* A config class used by the registry itself.
*
* Contains the parameters:
* waf.config.packages: comma separated package-key list of installed packages
* waf.config.parents :
*
* @author Rafael H. Schloming &lt;rhs@mit.edu&gt;
* @version $Id$
*/
public class RegistryConfig extends AbstractConfig {
/**
* Helper method to unmarshal parameter values.
* @param str A String of comma separated values
* @return StringArray of the values
*/
private static String[] array(String str) {
if (str == null) {
return null;
} else {
return StringUtils.split(str, ',');
}
}
/**
* List of installed packages.
*
* Provided as a comma separated package-key list of installed packages.
* The parameter overwrites the default marshal and unmarshal methods to
* allow the String parameter to hold a list of values.
*
* TODO: Replace the type String parameter by StringArray parameter which
* provides exactly the required functionality (doesn't it?).
*/
private Parameter m_packages = new StringParameter
("waf.config.packages", Parameter.OPTIONAL, new String[0]) {
@Override
protected Object unmarshal(String value, ErrorList errs) {
return array(value);
}
@Override
protected String marshal(Object obj) {
return StringUtils.join((String[]) obj, ',');
}
};
/**
* List of parameter values, purpose currently unkown.
*
* The parameter overwrites the default marshal and unmarshal methods to
* allow the String parameter to hold a list of values.
*/
private Parameter m_parents = new StringParameter
("waf.config.parents", Parameter.OPTIONAL, new URL[0]) {
@Override
protected Object unmarshal(String value, ErrorList errs) {
String[] strs = array(value);
URL[] result = new URL[strs.length];
for (int i = 0; i < result.length; i++) {
try {
result[i] = new URL(strs[i]);
} catch (MalformedURLException e) {
errs.add(new ParameterError(this, e));
}
}
if (!errs.isEmpty()) {
return null;
}
return result;
}
protected String marshal(Object obj) {
URL[] urls = (URL[]) obj;
String[] strs = new String[urls.length];
for (int i = 0; i < strs.length; i++) {
strs[i] = urls[i].toExternalForm();
}
return StringUtils.join(strs, ',');
}
};
/**
* Constructs a new and empty config object.
*/
public RegistryConfig() {
register(m_packages);
register(m_parents);
}
/**
* Returns the value of the waf.config.packages parameter.
*
* @return the value of the waf.config.packages parameter
*/
public String[] getPackages() {
return (String[]) get(m_packages);
}
/**
* Returns the value of the waf.config.parents parameter.
*
* @return the value of the waf.config.parents parameter
*/
public URL[] getParents() {
return (URL[]) get(m_parents);
}
}

View File

@ -0,0 +1,716 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util;
import org.apache.log4j.Logger;
/**
* Utility functions for assertions.
*
* <p>The static methods in this class provide a standard way of
* asserting certain conditions.</p>
*
* <p>Though it is not right now, this class <em>should</em> be final.
* Do not subclass it. In a future revision of this software, this
* class will be made final.</p>
*
* @author David Lutterkort &lt;dlutter@redhat.com&gt;
* @author Uday Mathur
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class Assert {
/** Class specific logger instance. */
private static final Logger s_log = Logger.getLogger(Assert.class);
private static final String DEFAULT_MESSAGE = "Assertion failure";
/**
* Configuration by a system wide / servlet container wide environment
* variable is evil and no longer supported API.
* Currently Assertion is set alway on. The non-deprecated methods of this
* class don't check for isEnabled anyway. So there is no effect.
* If configurability is really needed, configuration by config registry
* during system setup (eg. @link com.arsdigita.runtime.CCMResourceManager)
* has to be implemented
*/
private static boolean s_enabled = true;
// private static boolean s_enabled;
//
// static {
// final String enabled = System.getProperty
// (Assert.class.getName() + ".enabled");
//
// if (enabled == null) {
// //s_enabled = false;
// //default value is true
// s_enabled = true;
// } else {
// // s_enabled = enabled.equals("true");
// // Test: set to true anyway.
// // TODO: read from config registry, any dependency from a
// // environment variable is deprecated!
// s_enabled = true;
// }
// }
/**
* Tells whether asserts are turned on. Use this to wrap code
* that should be optimized away if assertions are disabled.
*
* By default, assertions are disabled
*/
public static final boolean isEnabled() {
return s_enabled;
}
static final void setEnabled(final boolean enabled) {
s_enabled = enabled;
}
/**
* Throws an error.
*
* @param message A <code>String</code> describing the failure
* condition
* @throws AssertionError
*/
public static final void fail(final String message) {
error(message);
throw new AssertionError(message);
}
/**
* Throws an error.
*
* @throws AssertionError
*/
public static final void fail() {
error(DEFAULT_MESSAGE);
throw new AssertionError(DEFAULT_MESSAGE);
}
/**
* Asserts that an arbitrary condition is true and throws an
* error with message <code>message</code> if the condition is
* false.
*
* @param condition The condition asserted
* @param message An error message
* @throws AssertionError if the condition is false
*/
public static final void isTrue(final boolean condition,
final String message) {
if (!condition) {
error(message);
throw new AssertionError(message);
}
}
/**
* Asserts that an arbitrary condition is true and throws an
* error with message <code>message</code> if the condition is
* false.
*
* @param condition The condition asserted
* @param message An error message
* @throws AssertionError if the condition is false
* @deprecated use Assert.isTrue(condition, message) instead
* (we will follow the standard naming scheme)
*/
public static final void truth(final boolean condition,
final String message) {
Assert.isTrue(condition, message);
// if (!condition) {
// error(message);
//
// throw new AssertionError(message);
// }
}
/**
* Asserts that an arbitrary condition is true and throws an
* error with message <code>message</code> if the condition is
* false.
*
* @param condition The condition asserted
* @throws AssertionError if the condition is false
*/
public static final void isTrue(final boolean condition) {
if (!condition) {
error(DEFAULT_MESSAGE);
throw new AssertionError(DEFAULT_MESSAGE);
}
}
/**
* Asserts that an arbitrary condition is true and throws an
* error with message <code>message</code> if the condition is
* false.
*
* @param condition The condition asserted
* @throws AssertionError if the condition is false
* @deprecated use Assert.isTrue(final boolean condition) instead
* (we will follow the standard naming scheme)
*/
public static final void truth(final boolean condition) {
Assert.isTrue(condition);
// if (!condition) {
// error(DEFAULT_MESSAGE);
//
// throw new AssertionError(DEFAULT_MESSAGE);
// }
}
/**
* Asserts that an arbitrary condition is false and throws an
* error if the condition is true.
*
* @param condition The condition asserted
* @param message An error message
* @throws AssertionError if the condition is false
*/
public static final void isFalse(final boolean condition,
final String message) {
if (condition) {
error(message);
throw new AssertionError(message);
}
}
/**
* Asserts that an arbitrary condition is false and throws an
* error if the condition is true.
*
* @param condition The condition asserted
* @throws AssertionError if the condition is false
*/
public static final void isFalse(final boolean condition) {
if (condition) {
error(DEFAULT_MESSAGE);
throw new AssertionError(DEFAULT_MESSAGE);
}
}
/**
* Asserts that an object is not null.
*
* @param object The object that must not be null
* @param clacc The <code>Class</code> of parameter
* <code>object</code>
* @throws AssertionError if the object is null
*/
public static void exists(final Object object,
final Class clacc) {
if (object == null) {
final String message = clacc.getName() + " is null";
error(message);
throw new AssertionError(message);
}
}
/**
* Asserts that an object is not null.
*
* @param object The <code>Object</code> that must not be null
* @param label A text to describe <code>Object</code>
*
* @throws AssertionError if the object is null
*/
public static void exists(final Object object,
final String label) {
if (object == null) {
final String message =
label != null && label.trim().length() > 0
? "Value of " + label + " is null."
: DEFAULT_MESSAGE ;
error(message);
throw new AssertionError(message);
}
}
/**
* Asserts that an object is not null.
*
* @param object The object that must not be null
* @throws AssertionError if the object is null
*/
public static final void exists(final Object object) {
if (object == null) {
error(DEFAULT_MESSAGE);
throw new AssertionError(DEFAULT_MESSAGE);
}
}
/**
* Verifies that <code>Lockable</code> is locked and throws an
* error if it is not.
*
* @param lockable The object that must be locked
* @see com.arsdigita.util.Lockable
*/
public static final void isLocked(final Lockable lockable) {
if (lockable != null && !lockable.isLocked()) {
final String message = "Illegal access: " + lockable +
" is not locked";
error(message);
throw new AssertionError(message);
}
}
/**
* Verifies that <code>lockable</code> is <em>not</em> locked and
* throws an error if it is.
*
* @param lockable The object that must not be locked
* @see com.arsdigita.util.Lockable
*/
public static final void isUnlocked(final Lockable lockable) {
if (lockable != null && lockable.isLocked()) {
final String message = "Illegal access: " + lockable + " is locked.";
error(message);
throw new AssertionError(message);
}
}
/**
* Verifies that two values are equal (according to their equals
* method, unless <code>value1</code> is null, then according to
* <code>==</code>).
*
* @param value1 The first value to be compared
* @param value2 The second
* @throws AssertionError if the arguments are unequal
*/
public static final void isEqual(final Object value1,
final Object value2) {
if (value1 == null) {
if (value1 != value2) {
final String message = value1 + " does not equal " + value2;
error(message);
throw new AssertionError(message);
}
} else {
if (!value1.equals(value2)) {
final String message = value1 + " does not equal " + value2;
error(message);
throw new AssertionError(message);
}
}
}
/**
* Verifies that two values are equal (according to their equals
* method, unless <code>value1</code> is null, then according to
* <code>==</code>).
*
* @param value1 The first value to be compared
* @param value2 The second
* @throws AssertionError if the arguments are unequal
*/
public static final void isEqual(final Object value1,
final Object value2,
final String message) {
if (value1 == null) {
if (value1 != value2) {
error(message);
throw new AssertionError(message);
}
} else {
if (!value1.equals(value2)) {
error(message);
throw new AssertionError(message);
}
}
}
/**
* Verifies that two values are not equal (according to their
* equals method, unless <code>value1</code> is null, then
* according to <code>==</code>).
*
* @param value1 The first value to be compared
* @param value2 The second
* @throws AssertionError if the arguments are isNotEqual
*/
public static final void isNotEqual(final Object value1,
final Object value2) {
if (value1 == null) {
if (value1 == value2) {
final String message = value1 + " equals " + value2;
error(message);
throw new AssertionError(message);
}
} else {
if (value1.equals(value2)) {
final String message = value1 + " equals " + value2;
error(message);
throw new AssertionError(message);
}
}
}
// Utility methods
private static void error(final String message) {
// Log the stack trace too, since we still have code that
// manages to hide exceptions.
s_log.error(message, new AssertionError(message));
}
///////////////////////////////////////////////////////////////////////////
// //
// The methods below are all deprecated. //
// //
///////////////////////////////////////////////////////////////////////////
/**
* @deprecated in favor of {@link #isEnabled()}
*
* pboy Jan.09: not used by any package in trunk
*/
// public static final boolean ASSERT_ON = true;
/**
* Indicates state of the ASSERT_ON flag.
*
* pboy Jan.09: not used by any package in trunk
*
* @deprecated Use {@link #isEnabled()} instead
*/
// public static final boolean isAssertOn() {
// return isEnabled();
// }
// /**
// * Tells whether asserts are turned on. Use this to wrap code
// * that should be optimized away if asserts are disabled.
// *
// * @deprecated Use {@link #isEnabled()} instead
// */
// public static final boolean isAssertEnabled() {
// return isEnabled();
// }
/**
* Assert that an arbitrary condition is true, and throw an
* exception if the condition is false.
*
* @param cond condition to assert
* @throws java.lang.IllegalStateException condition was false
* @deprecated Use {@link #truth(boolean, String)} instead
*/
/* public static final void isTrue(boolean cond) {
isTrue(cond, "");
}
*/
/**
* Assert that an arbitrary condition is true, and throw an
* exception with message <code>msg</code> if the condition is
* false.
*
* @param cond condition to assert
* @param msg failure message
* @throws java.lang.IllegalStateException condition was false
* @deprecated Use {@link #truth(boolean,String)} instead
*/
/* public static final void assertTrue(boolean cond, String msg) {
if (!cond) {
error(msg);
throw new IllegalStateException(msg);
}
}
*/
/**
* Asserts that an arbitrary condition is true and throws an
* error with message <code>message</code> if the condition is
* false.
*
* @param condition The condition asserted
* @param message An error message
* @throws AssertionError if the condition is false
* @deprecated use Assert.isTrue(condition, message) instead
* (we will follow the standard naming scheme)
*/
/* public static final void truth(final boolean condition,
final String message) {
Assert.isTrue(condition, message);
// if (!condition) {
// error(message);
//
// throw new AssertionError(message);
// }
}
*/
/**
* Asserts that an arbitrary condition is true and throws an
* error with message <code>message</code> if the condition is
* false.
*
* @param condition The condition asserted
* @throws AssertionError if the condition is false
* @deprecated use Assert.isTrue(final boolean condition) instead
* (we will follow the standard naming scheme)
*/
/* public static final void truth(final boolean condition) {
Assert.isTrue(condition);
// if (!condition) {
// error(DEFAULT_MESSAGE);
//
// throw new AssertionError(DEFAULT_MESSAGE);
// }
}
*/
/**
* Asserts that an arbitrary condition is false and throws an
* error if the condition is true.
*
* @param condition The condition asserted
* @param message An error message
* @throws AssertionError if the condition is false
*/
/* public static final void falsity(final boolean condition,
final String message) {
if (condition) {
error(message);
throw new AssertionError(message);
}
}
*/
/**
* Asserts that an arbitrary condition is false and throws an
* error if the condition is true.
*
* @param condition The condition asserted
* @throws AssertionError if the condition is false
*/
/* public static final void falsity(final boolean condition) {
if (condition) {
error(DEFAULT_MESSAGE);
throw new AssertionError(DEFAULT_MESSAGE);
}
}
*/
/**
* Verify that a parameter is not null and throw a runtime
* exception if so.
*
* @deprecated Use {@link #exists(Object)} instead
*/
/* public static final void assertNotNull(Object o) {
assertNotNull(o, "");
}
*/
/**
* Verify that a parameter is not null and throw a runtime
* exception if so.
*
* @deprecated Use {@link #exists(Object,String)} instead
*/
/* public static final void assertNotNull(Object o, String label) {
if (isEnabled()) {
isTrue(o != null, "Value of " + label + " is null.");
}
}
*/
// /**
// * Verify that a string is not empty and throw a runtime exception
// * if so. A parameter is considered empty if it is null, or if it
// * does not contain any characters that are non-whitespace.
// *
// * @deprecated with no replacement
// */
// public static final void assertNotEmpty(String s) {
// assertNotEmpty(s, "");
// }
/**
* Verify that a string is not empty and throw a runtime exception
* if so. A parameter is considered empty if it is null, or if it
* does not contain any characters that are non-whitespace.
*
* @deprecated with no replacement
*/
public static final void assertNotEmpty(String s, String label) {
if (isEnabled()) {
isTrue(s != null && s.trim().length() > 0,
"Value of " + label + " is empty.");
}
}
/**
* Verify that two values are equal (according to their equals method,
* unless expected is null, then according to ==).
*
* @param expected Expected value.
* @param actual Actual value.
* @throws java.lang.IllegalStateException condition was false
* @deprecated Use {@link #isEqual(Object,Object)} instead
*/
public static final void assertEquals(Object expected, Object actual) {
assertEquals(expected, actual, "expected", "actual");
}
/**
* Verify that two values are equal (according to their equals method,
* unless expected is null, then according to ==).
*
* @param expected Expected value.
* @param actual Actual value.
* @param expectedLabel Label for first (generally expected) value.
* @param actualLabel Label for second (generally actual) value.
* @throws java.lang.IllegalStateException condition was false
*/
public static final void assertEquals(Object expected, Object actual,
String expectedLabel,
String actualLabel) {
if (isEnabled()) {
if (expected == null) {
isTrue(expected == actual,
"Values not equal, " +
expectedLabel + " '" + expected + "', " +
actualLabel + " '" + actual + "'");
} else {
isTrue(expected.equals(actual),
"Values not equal, " +
expectedLabel + " '" + expected + "', " +
actualLabel + " '" + actual + "'");
}
}
}
/**
* Verify that two values are equal.
*
* @param expected Expected value.
* @param actual Actual value.
* @throws java.lang.IllegalStateException condition was false
* @deprecated Use {@link #truth(boolean, String)} instead
*/
public static final void assertEquals(int expected, int actual) {
assertEquals(expected, actual, "expected", "actual");
}
/**
* Verify that two values are equal.
*
* @param expected Expected value.
* @param actual Actual value.
* @param expectedLabel Label for first (generally expected) value.
* @param actualLabel Label for second (generally actual) value.
* @throws java.lang.IllegalStateException condition was false
* @deprecated Use {@link #truth(boolean, String)} instead
*/
public static final void assertEquals(int expected, int actual,
String expectedLabel,
String actualLabel) {
if (isEnabled()) {
isTrue(expected == actual,
"Values not equal, " +
expectedLabel + " '" + expected + "', " +
actualLabel + " '" + actual + "'");
}
}
/**
* Verify that the model is locked and throw a runtime exception
* if it is not locked.
*
* @deprecated Use {@link #isLocked(Lockable)} instead
*/
/* public static void assertLocked(Lockable l) {
if (isEnabled()) {
isTrue(l.isLocked(),
"Illegal access to an unlocked " +
l.getClass().getName());
}
}
*/
/**
* Verify that the model is locked and throw a runtime exception
* if it is locked.
*
// * @deprecated Use {@link #isUnlocked(Lockable)} instead
*/
/* public static void assertUnlocked(Lockable l) {
if (isEnabled()) {
isTrue(!l.isLocked(),
"Illegal access to a isLocked " +
l.getClass().getName());
}
}
*/
/**
* Verifies that <code>lockable</code> is <em>not</em> isLocked and
* throws an error if it is.
*
* @param lockable The object that must not be isLocked
* @see com.arsdigita.util.Lockable
// * @deprecated use isUnlocked(Lockable) instead
*/
/* public static final void unlocked(final Lockable lockable) {
if (lockable != null && lockable.isLocked()) {
final String message = "Illegal access: " + lockable + " is isLocked.";
error(message);
throw new AssertionError(message);
}
}
*/
}

View File

@ -0,0 +1,148 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Constructor;
import org.apache.log4j.Logger;
import java.util.Arrays;
/**
* A collection of static utility methods for dealing with Java
* classes.
*
* @author Justin Ross
* @version $Id$
*/
public final class Classes {
private static final Logger s_log = Logger.getLogger(Classes.class);
/**
* Loads a class from its fully qualified string name.
*
* @param clacc A fully qualified <code>String</code> naming
* the class to be loaded
*/
public static final Class loadClass(final String clacc) {
Assert.exists(clacc, String.class);
try {
return Class.forName(clacc);
} catch (ClassNotFoundException ex) {
throw new UncheckedWrapperException(ex);
}
}
/**
* Constructs a new instance of a class using the given
* parameters.
*
* @param clacc The <code>Class</code> of which to make a new
* instance
* @param params A <code>Class[]</code> representing the arguments
* of the desired constructor
* @param values An <code>Object[]</code> of values to fill the
* parameters
*/
public static final Object newInstance(final Class clacc,
final Class[] params,
final Object[] values) {
if (Assert.isEnabled()) {
Assert.exists(clacc, Class.class);
Assert.exists(params, Class.class);
Assert.exists(values, Object.class);
Assert.isTrue(params.length == values.length);
}
try {
final Constructor constructor = clacc.getConstructor(params);
return constructor.newInstance(values);
} catch (NoSuchMethodException ex) {
throw new UncheckedWrapperException
(message(clacc, params, values), ex);
} catch (IllegalAccessException ex) {
throw new UncheckedWrapperException
(message(clacc, params, values), ex);
} catch (InvocationTargetException ex) {
throw new UncheckedWrapperException
(message(clacc, params, values), ex);
} catch (InstantiationException ex) {
throw new UncheckedWrapperException
(message(clacc, params, values), ex);
}
}
private static String message(Class klass, Class[] params,
Object[] values) {
return "class = " + klass +
", params = " + message(params) +
", values = " + message(values);
}
private static String message(Object[] array) {
if (array == null) {
return "" + null;
} else {
return Arrays.asList(array).toString();
}
}
/**
* Constructs a new instance of the class referred to by
* <code>clacc</code>.
*
* @param clacc The fully qualified <code>String</code>
* clacc of the object you wish to instantiate
* @param params A <code>Class[]</code> representing the arguments
* of the desired constructor
* @param values An <code>Object[]</code> of values to fill the
* parameters
*/
public static final Object newInstance(final String clacc,
final Class[] params,
final Object[] values) {
return newInstance(loadClass(clacc), params, values);
}
/**
* Creates a new instance of <code>clacc</code> using its no-args
* constructor. If the class has no such constructor, it throws a
* runtime exception.
*
* @param clacc The class of which to create a new instance
*/
public static final Object newInstance(final Class clacc) {
return newInstance(clacc, new Class[0], new Object[0]);
}
/**
* Creates a new instance of the class represented by
* <code>clacc</code> using its no-args constructor. If the class
* has no such constructor, it throws a runtime exception.
*
* @param clacc The fully-qualified <code>String</code> name of
* the class
*/
public static final Object newInstance(final String clacc) {
return newInstance(loadClass(clacc));
}
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util;
public interface ExceptionUnwrapper {
Throwable unwrap(Throwable t);
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import org.apache.log4j.Logger;
public class Exceptions {
private static Logger s_log = Logger.getLogger(Exceptions.class);
private static Map s_unwrappers = new HashMap();
public static Throwable[] unwrap(Throwable t) {
Assert.exists(t, Throwable.class);
List exceptions = new ArrayList();
exceptions.add(t);
if (s_log.isDebugEnabled()) {
s_log.debug("Trying to unwrap " + t.getClass());
}
Throwable current = t;
for (;;) {
Throwable inner = null;
ExceptionUnwrapper unwrapper = findUnwrapper(current.getClass());
if (unwrapper != null) {
inner = unwrapper.unwrap(current);
}
if (inner == null) {
Assert.exists(current, Throwable.class);
if (s_log.isDebugEnabled()) {
s_log.debug("Returning exception " + current.getClass());
}
return (Throwable[])exceptions.toArray(
new Throwable[exceptions.size()]);
}
if (s_log.isDebugEnabled()) {
s_log.debug("Inner exception is " + inner.getClass());
}
exceptions.add(inner);
current = inner;
}
// Unreachable
//throw new RuntimeException("this cannot happen");
}
public static void registerUnwrapper(Class exception,
ExceptionUnwrapper unwrapper) {
s_unwrappers.put(exception, unwrapper);
}
public static void unregisterUnwrapper(Class exception) {
s_unwrappers.remove(exception);
}
public static ExceptionUnwrapper getUnwrapper(Class exception) {
return (ExceptionUnwrapper)s_unwrappers.get(exception);
}
public static ExceptionUnwrapper findUnwrapper(Class exception) {
if (s_log.isDebugEnabled()) {
s_log.debug("Finding unwrapper for " + exception.getName());
}
Class current = exception;
ExceptionUnwrapper unwrapper = null;
while (unwrapper == null &&
current != null) {
if (s_log.isDebugEnabled()) {
s_log.debug("Trying class " + current.getName());
}
unwrapper = (ExceptionUnwrapper)s_unwrappers.get(current);
current = current.getSuperclass();
}
if (s_log.isDebugEnabled()) {
s_log.debug("Got unwrapper " +
(unwrapper != null ? unwrapper.getClass() : null));
}
return unwrapper;
}
}

View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util;
import com.arsdigita.util.parameter.ErrorList;
import com.arsdigita.util.parameter.Parameter;
import com.arsdigita.util.parameter.ParameterReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.apache.log4j.Logger;
/**
* An implementation of <code>ParameterReader</code> that uses
* standard Java properties to retrieve values.
*
* Subject to change.
*
* @see com.arsdigita.util.parameter.ParameterReader
* @see JavaPropertyWriter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class JavaPropertyReader implements ParameterReader {
private static final Logger s_log = Logger.getLogger
(JavaPropertyReader.class);
private final Properties m_props;
/**
* Constructs a parameter reader that uses <code>props</code>.
*
* @param props The <code>Properties</code> object that stores
* property values; it cannot be null
*/
public JavaPropertyReader(final Properties props) {
Assert.exists(props, Properties.class);
m_props = props;
}
/**
* Loads the internal <code>Properties</code> object using
* <code>in</code>.
*
* @param in The <code>InputStream</code> that has the source
* properties; it cannot be null
*/
public final void load(final InputStream in) {
Assert.exists(in, InputStream.class);
try {
m_props.load(in);
} catch (IOException ioe) {
throw new UncheckedWrapperException(ioe);
}
}
/**
* Reads a <code>String</code> value back for a
* <code>param</code>.
*
* @param param The <code>Parameter</code> whose value is
* requested; it cannot be null
* @param errors An <code>ErrorList</code> to trap any errors
* encountered when reading; it cannot be null
* @return The <code>String</code> value for <code>param</code>;
* it can be null
*/
@Override
public final String read(final Parameter param, final ErrorList errors) {
if (s_log.isDebugEnabled()) {
s_log.debug("Reading " + param + " from " + m_props);
}
if (Assert.isEnabled()) {
Assert.exists(param, Parameter.class);
Assert.exists(errors, ErrorList.class);
}
return m_props.getProperty(param.getName());
}
/**
* Returns a <code>String</code> representation of this object.
*
* @return super.toString() + "," + properties.size()
*/
@Override
public String toString() {
return super.toString() + "," + m_props.size();
}
}

View File

@ -0,0 +1,119 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util;
import com.arsdigita.util.parameter.Parameter;
import com.arsdigita.util.parameter.ParameterWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
import org.apache.log4j.Logger;
/**
* Subject to change.
*
* An implementation of <code>ParameterWriter</code> that uses
* standard Java properties to store values.
*
* @see com.arsdigita.util.parameter.ParameterWriter
* @see JavaPropertyReader
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class JavaPropertyWriter implements ParameterWriter {
private static final Logger s_log = Logger.getLogger
(JavaPropertyWriter.class);
private static final String s_header =
" Generated by " + JavaPropertyWriter.class.getName();
private final Properties m_props;
/**
* Constructs a parameter writer that uses <code>props</code>.
*
* @param props The <code>Properties</code> object that stores
* property values; it cannot be null
*/
public JavaPropertyWriter(final Properties props) {
Assert.exists(props, Properties.class);
m_props = props;
}
/**
* Tells the internal property object to store its values to
* <code>out</code>.
*
* @param out The <code>OutputStream</code> to send the saved
* parameters to; it cannot be null
*/
public final void store(final OutputStream out) {
if (s_log.isDebugEnabled()) {
s_log.debug("Storing " + this);
}
Assert.exists(out, OutputStream.class);
try {
m_props.store(out, s_header);
} catch (IOException ioe) {
throw new UncheckedWrapperException(ioe);
}
}
/**
* Writes a <code>String</code> value back for a
* <code>param</code>.
*
* @param param The <code>Parameter</code> whose value is
* to be written; it cannot be null
* @param value The <code>String</code> value to write out; it can
* be null
*/
public final void write(final Parameter param, final String value) {
if (s_log.isDebugEnabled()) {
s_log.debug("Writing " + param + " with value " + value);
}
if (Assert.isEnabled()) {
Assert.exists(param, Parameter.class);
}
// XXX: Properties objects blow up when you try to put null
// values in them. This null check fixes it for now, but it
// doesn't let us explicitly write out a null value if that's
// what we actually want to store. I.e. our property store
// doesn't know the difference between a parameter being
// unspecified and a parameter being explicitly set to null.
if (value != null) {
m_props.setProperty(param.getName(), value);
}
}
/**
* Returns a <code>String</code> representation of this object.
*
* @return super.toString() + "," + properties.size()
*/
public String toString() {
return super.toString() + "," + m_props.size();
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util;
/**
* A common interface for all lockable parts of ACS. The locking mechanism makes
* it possible to safely split all data structures that are used inside a web
* server into ones that are constant across all requests and those that may
* change during a request.
*
* <p>
* The distinction betwen static and request-specific data helps in optimizing
* the amount of memory that needs to be allocated for each request. Data
* structures that are static can be allocated and initialized ahead of time,
* e.g., in the <code>init</code> method of a servlet. The initialized data
* structures are then <em>locked</em> to make them immutable. This mechanism
* ensures that static structures that are supposed to be shared by many
* requests, often even concurrently, do not change and are not "polluted" by
* request-specific data.
*
* <p>
* There is no automatic mechanism that makes an object immutable by itself. The
* right checks and operations need to be implemented by each class implementing
* <code>Lockable</code>.
*
* <p>
* Bebop parameters are a good example of how one logical structure is split
* into two classes: the class {@link
* com.arsdigita.bebop.parameters.ParameterModel} is <code>Lockable</code> and
* only contains the description of the parameter in an HTTP request that is
* static and does not change on a per-request basis, such as the name of the
* parameter and the (Java) type that the parameter value should be converted
* to. The class {@link
* com.arsdigita.bebop.parameters.ParameterData} contains all the
* request-specific information for a parameter, such as the value of the
* parameter.
*
* <p>
* Any class that implements <code>Lockable</code> is expected to be fully
* modifiable until its {@link #lock} method is called. From that point on, it
* is read-only and should throw exceptions whenever an attempt is made to
* modify it.
*
* @author David Lutterkort
* @version $Id$
*/
public interface Lockable {
/**
* Lock an object. Locked objects are to be considered immutable. Any
* attempt to modify them, e.g., through a <code>setXXX</code> method should
* lead to an exception.
*
* <p>
* Most lockable Bebop classes throw an {@link
* java.lang.IllegalStateException} if an attempt is made to modify a locked
* instance.
*/
void lock();
/**
* Return whether an object is locked and thus immutable, or can still be
* modified.
*
* @return
*/
boolean isLocked();
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util;
/**
* A generic implementation of the Lockable interface.
*
* @see Lockable
*
* @author Michael Bryzek
* @version $Id$
*
*/
public class LockableImpl implements Lockable {
private boolean m_locked = false;
/**
* Lock an object. Locked objetcs are to be considered immutable. Any
* attempt to modify them, e.g., through a <code>setXXX</code> method should
* lead to an exception.
*
* @see Lockable#lock()
*
*/
// must not be final so cms.ui.Grid.GridModelBuilder can override it.
@Override
public void lock() {
m_locked = true;
}
/**
* Return whether an object is locked and thus immutable, or can still be
* modified.
*
* @return
*
* @see Lockable#isLocked()
*
*/
// must not be final so cms.ui.PropertySheet.PSTMBAdapter can override it.
@Override
public boolean isLocked() {
return m_locked;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,207 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util;
import org.apache.log4j.Logger;
/**
* A wrapper exception that can be used to rethrow another
* exception.
*
* TODO: This should become a skeleton when/if we switch to Java 1.4.
* http://java.sun.com/j2se/1.4/docs/guide/lang/chained-exceptions.html
*
* The basic exception methods are overridden with methods that
* combine this wrapper and its root cause, so it can be
* treated just like any normal exception in actual use.
*
* Note that it is not necessary to provide a string along
* with a root cause; in particular, the following usage:
* <tt>new UncheckedWrapperException(e);</tt> is more correct than
* <tt>new UncheckedWrapperException(e.getMessage(), e);</tt>
*
* @author David Eison
* @version $Id$
*/
public class UncheckedWrapperException extends RuntimeException {
private static final Logger logger = Logger.getLogger(
UncheckedWrapperException.class);
static {
logger.debug("Static initalizer starting...");
Exceptions.registerUnwrapper(
UncheckedWrapperException.class,
new ExceptionUnwrapper() {
public Throwable unwrap(Throwable t) {
UncheckedWrapperException ex =
(UncheckedWrapperException) t;
return ex.getRootCause();
}
});
logger.debug("Static initalizer finished.");
}
Throwable m_rootCause;
/**
* Constructor which only takes a msg, which will cause this
* UncheckedWrapperException to behave like a normal RuntimeException.
* While it doesn't seem to make a lot of sense to have a wrapper
* exception that doesn't wrap anything, this is needed so that it
* can be used as a direct replacement for RuntimeException.
*/
public UncheckedWrapperException(String msg) {
this(msg, null);
}
/**
* Constructor which takes a root cause
* that this exception will be wrapping.
*/
public UncheckedWrapperException(Throwable rootCause) {
this(null, rootCause);
}
/**
* Constructor which takes a message string and a root cause
* that this exception will be wrapping. The message string
* should be something different than rootCause.getMessage()
* would normally provide.
*/
public UncheckedWrapperException(String s, Throwable rootCause) {
super(s);
this.m_rootCause = rootCause;
}
/**
* Throws an UncheckedWrapperException, and ensurs that it is logged at ERROR priority.
*
* @param source Class having the error. For Log4J reporting
* @param msg Error message
* @param rootCause The root cause exception
*
* @throws UncheckedWrapperException
*/
public static void throwLoggedException(Class source, String msg,
Throwable rootCause) throws
UncheckedWrapperException {
Logger log = Logger.getLogger(source);
log.error(msg, rootCause);
throw new UncheckedWrapperException(msg, rootCause);
}
/**
* Indicates if this exception has a root cause.
*/
public boolean hasRootCause() {
return m_rootCause != null;
}
/**
* Gets the root cause of this exception.
*/
public Throwable getRootCause() {
return m_rootCause;
}
// All further methods override normal throwable behavior to
// combine information w/ the root cause.
/**
* Get a string representing this exception and the root cause.
*/
@Override
public String toString() {
return toString(this.getClass());
}
/**
* Get a string representing this exception and the root cause.
*
* Functions like normal toString, except that the name of the
* provided class will be used instead of the name of the
* unchecked wrapper exception. Useful when another exception
* class is using an unchecked wrapper exception to delegate
* to.
*/
public String toString(Class delegatingClass) {
// default toString calls getMessage, so we don't want to rely on it
// here.
StringBuffer b = new StringBuffer(delegatingClass.getName());
String superMsg = super.getMessage();
if (superMsg != null) {
b.append(": ").append(superMsg);
}
if (m_rootCause != null) {
b.append(" (root cause: ").append(m_rootCause.toString());
b.append(")");
}
return b.toString();
}
/**
* This exception's message and the root cause's.
*/
@Override
public String getMessage() {
if (m_rootCause != null) {
return super.getMessage() + " (root cause: " + m_rootCause.
getMessage() + ")";
} else {
return super.getMessage();
}
}
/**
* Stack trace for the root cause.
*/
@Override
public void printStackTrace() {
super.printStackTrace();
if (m_rootCause != null) {
System.err.print("Root cause: ");
m_rootCause.printStackTrace();
}
}
/**
* Stack trace for the root cause.
*/
@Override
public void printStackTrace(java.io.PrintStream s) {
super.printStackTrace(s);
if (m_rootCause != null) {
s.println("Root cause: ");
m_rootCause.printStackTrace(s);
}
}
/**
* Stack trace for the root cause.
*/
@Override
public void printStackTrace(java.io.PrintWriter s) {
super.printStackTrace(s);
if (m_rootCause != null) {
s.println("Root cause: ");
m_rootCause.printStackTrace(s);
}
}
}

View File

@ -0,0 +1,339 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import com.arsdigita.util.Assert;
import org.apache.commons.beanutils.ConversionException;
/**
* A base implementation of the <code>Parameter</code> interface.
*
* It offers subclasses use of the Apache BeanUtils framework, should
* they opt to use it.
*
* Methods of the form <code>doXXX</code> are extension points for subclasses.
* The <code>isRequired()</code> and <code>getDefaultValue()</code>
* methods may also be overriden.
*
* Subject to change.
*
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public abstract class AbstractParameter implements Parameter {
private final String m_name;
private final Class m_type;
private final int m_multiplicity;
private final Object m_default;
private ParameterInfo m_info;
/**
* Constructs a new parameter with the default value
* <code>defaalt</code> and using the beanutils converter
* registered for <code>type</code>.
*
* @param name The name of the parameter; it cannot be null
* @param multiplicity The multiplicity type of the parameter
* @param defaalt The default value to use if the value is unset
* or is null
* @param type The <code>Class</code> whose beanutils converter
* will be used to unmarshal literal values
*/
protected AbstractParameter(final String name,
final int multiplicity,
final Object defaalt,
final Class type) {
if (Assert.isEnabled()) {
Assert.exists(name, String.class);
}
m_name = name;
m_type = type;
m_multiplicity = multiplicity;
m_default = defaalt;
}
/**
* Constructs a new parameter with the default value
* <code>defaalt</code>.
*
* @param name The name of the parameter; it cannot be null
* @param multiplicity The multiplicity type of the parameter
* @param defaalt The default value to use if the value is unset
* or is null
*/
protected AbstractParameter(final String name,
final int multiplicity,
final Object defaalt) {
// XXX Get rid of this constructor?
this(name, multiplicity, defaalt, null);
}
/**
* Constructs a new parameter using the beanutils converter for
* type <code>type</code>. By default, the parameter is required
* and has no default.
*
* @param name The name of the parameter; it cannot be null
* @param type The <code>Class</code> whose beanutils converter
* will be used to unmarshal literal values
*/
protected AbstractParameter(final String name,
final Class type) {
this(name, Parameter.REQUIRED, null, type);
}
/**
* Parameter users may override this method to make the multiplicity of
* the parameter dependent on the multiplicity of related parameters.
*
* @see Parameter#isRequired()
*/
public boolean isRequired() {
return m_multiplicity == Parameter.REQUIRED;
}
/**
* @see Parameter#getName()
*/
public final String getName() {
return m_name;
}
/**
* Parameter users may override this method to achieve dynamic
* defaulting.
*
* @see Parameter#getDefaultValue()
*/
public Object getDefaultValue() {
return m_default;
}
/**
* @see Parameter#getInfo()
*/
public final ParameterInfo getInfo() {
return m_info;
}
/**
* @see Parameter#setInfo(ParameterInfo)
*/
public final void setInfo(final ParameterInfo info) {
m_info = info;
}
//
// Lifecycle events
//
/**
* Gets the parameter value as a Java object.
*
* The value will have a specific runtime type and so may be
* appropriately cast.
*
* Reading typically follows the following procedure:
*
* <ul>
* <li>Read the literal string value associated with the
* parameter from <code>reader</code></li>
*
* <li>Convert the literal string value into an approprite Java
* object</li>
* </ul>
*
* If at any point in the process an error is encountered, it is
* added to <code>errors</code>. Callers of this method will
* typically construct an <code>ErrorList</code> in which to
* collect errors.
* Actually calls {@link #doRead(ParameterReader,ErrorList)} (as an
* extension point for subclasses).
*
* @param reader The <code>ParameterReader</code> from which to
* recover a string literal value; it cannot be null
* @param errors The <code>ErrorList</code> in which to collect
* any errors encountered; it cannot be null
* @return The Java object value of the parameter
*
*/
public final Object read(final ParameterReader reader,
final ErrorList errors) {
if (Assert.isEnabled()) {
Assert.exists(reader, ParameterReader.class);
Assert.exists(errors, ErrorList.class);
}
return doRead(reader, errors);
}
/**
* Extension point to read the value of the parameter from <code>reader</code>.
*
* It unmarshals the value, and returns it. If any errors are encountered,
* they are added to <code>errors</code>.
*
* If the literal string value from <code>reader</code> is not null,
* this method delegates to {@link #unmarshal(String,ErrorList)}.
*
* This implementation is suited to a parameter with a singular
* scalar value. Subclasses that are compound parameters should
* override this method to delegate to child parameters.
*
* @param reader The <code>ParameterReader</code> that will supply
* the literal stored value for this parameter; it cannot be null
* @param errors The <code>ErrorList</code> that will trap any
* errors encountered; it cannot be null
*/
protected Object doRead(final ParameterReader reader,
final ErrorList errors) {
final String string = reader.read(this, errors);
if (string == null) {
return null;
} else {
return unmarshal(string, errors);
}
}
/**
* Converts a literal <code>String</code> value,
* <code>value</code>, to a Java object, which is returned.
*
* @param value The <code>String</code> value to convert from; it
* cannot be null
* @param errors An <code>ErrorList</code> that holds any errors
* encountered during unmarshaling; it cannot be null
*/
protected Object unmarshal(final String value, final ErrorList errors) {
if (Assert.isEnabled()) {
Assert.exists(value, String.class);
Assert.exists(errors, String.class);
}
try {
return Converters.convert(m_type, value);
} catch (ConversionException ce) {
errors.add(new ParameterError(this, ce));
return null;
}
}
/**
* Calls {@link #doValidate(Object,ErrorList)} if
* <code>value</code> is not null. Otherwise, if the value is
* <em>required and null</em>, an error is added to
* <code>errors</code> and <code>doValidate</code> is not called.
*
* @see Parameter#validate(Object,ErrorList)
*/
public final void validate(final Object value, final ErrorList errors) {
Assert.exists(errors, ErrorList.class);
if (value == null) {
// If the value is null, validation stops here.
if (isRequired()) {
final ParameterError error = new ParameterError
(this, "The value must not be null");
errors.add(error);
}
} else {
// Always do further validation for non-null values.
doValidate(value, errors);
}
}
/**
* Validates <code>value</code>, placing any validation errors in
* <code>errors</code>. This particular implementation does
* nothing. Subclasses are expected to add specific validation
* behaviors.
*
* @param value The value to validate; it cannot be null
* @param errors The <code>ErrorList</code> that traps validation
* errors; it cannot be null
*/
protected void doValidate(final Object value, final ErrorList errors) {
if (Assert.isEnabled()) {
Assert.exists(value, Object.class);
Assert.exists(errors, ErrorList.class);
}
// Nothing
}
/**
* Calls {@link #doWrite(ParameterWriter,Object)}.
*
* @see Parameter#write(ParameterWriter,Object)
*/
public final void write(final ParameterWriter writer, final Object value) {
Assert.exists(writer);
// XXX what to do about nulls here?
doWrite(writer, value);
}
/**
* Marshals and writes <code>value</code> to <code>writer</code>.
*
* This implementation is suited to a parameter with a singular
* scalar value. Subclasses that are compound parameters should
* override this method to delegate to child parameters.
*
* @param writer The <code>ParameterWriter</code> we write to; it
* cannot be null
* @param value The value to write; it may be null
*/
protected void doWrite(final ParameterWriter writer, final Object value) {
writer.write(this, marshal(value));
}
/**
* Converts <code>value</code> to a representative
* <code>String</code>, which is returned.
*
* @param value The value to marshal; it may be null
* @return The <code>String</code> literal representation of
* <code>value</code>; it may be null
*/
protected String marshal(final Object value) {
if (value == null) {
return null;
} else {
return value.toString();
}
}
/**
* Returns a <code>String</code> representation of this object.
*
* @return <code>super.toString() + "," + getName() + "," +
* isRequired()</code>
*/
public String toString() {
return super.toString() + "," + getName() + "," + isRequired();
}
}

View File

@ -0,0 +1,307 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import com.arsdigita.util.Assert;
import com.arsdigita.util.UncheckedWrapperException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.log4j.Logger;
/**
* A base implementation of the <code>ParameterContext</code>
* interface.
*
* Subject to change.
*
* @see com.arsdigita.util.parameter.ParameterContext
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public abstract class AbstractParameterContext implements ParameterContext {
private static final Logger s_log = Logger.getLogger
(AbstractParameterContext.class);
private final MapParameter m_param;
private final HashMap m_map;
private final Properties m_info;
/**
* Constructs a parameter context.
*/
public AbstractParameterContext() {
m_param = new MapParameter("root");
m_map = new HashMap();
m_info = new Properties();
}
/**
* Registers <code>param</code> to the context.
*
* @param param The <code>Parameter</code> being registered; it
* cannot be null
*/
public final void register(final Parameter param) {
if (s_log.isDebugEnabled()) {
s_log.debug("Registering " + param + " on " + this);
}
if (Assert.isEnabled()) {
Assert.exists(param, Parameter.class);
Assert.isTrue(!m_param.contains(param),
param + " is already registered");
}
m_param.add(param);
}
/**
* @see ParameterContext#getParameters()
*/
public final Parameter[] getParameters() {
final ArrayList list = new ArrayList();
final Iterator params = m_param.iterator();
while (params.hasNext()) {
list.add(params.next());
}
return (Parameter[]) list.toArray(new Parameter[list.size()]);
}
/**
* Gets the unmarshaled value of <code>param</code>.
*
* If the loaded value is null, <code>param.getDefaultValue()</code>
* is returned.
*
* @param param The named <code>Parameter</code> whose value to
* retrieve; it cannot be null
* @return The unmarshaled Java object value of <code>param</code>
*/
public Object get(final Parameter param) {
return get(param, param.getDefaultValue());
}
/**
* Gets the unmarshaled value of <code>param</code>, returning
* <code>dephalt</code> if <code>param</code>'s value is null.
*
* @param param The <code>Parameter</code> whose value to
* retrieve; it cannot be null
* @param dephalt The fallback default value; it may be null
* @return The unmarshaled Java object value of <code>param</code>
* or <code>dephalt</code> if the former is null
*/
public Object get(final Parameter param, final Object dephault) {
if (Assert.isEnabled()) {
Assert.exists(param, Parameter.class);
Assert.isTrue(m_param.contains(param),
param + " has not been registered");
}
// XXX check for is loaded?
final Object value = m_map.get(param);
if (value == null) {
return dephault;
} else {
return value;
}
}
/**
* @see ParameterContext#get(Parameter,Object)
*/
public void set(final Parameter param, final Object value) {
if (s_log.isDebugEnabled()) {
s_log.debug("Setting " + param + " to " + value);
}
Assert.exists(param, Parameter.class);
m_map.put(param, value);
}
/**
* Reads and unmarshals all values associated with the registered
* parameters from <code>reader</code>. Any errors are returned.
*
* @param reader The <code>ParameterReader</code> from which to
* fetch the values; it cannot be null
* @return An <code>ErrorList</code> containing any errors
* encountered while loading; it cannot be null
*/
public final ErrorList load(final ParameterReader reader) {
final ErrorList errors = new ErrorList();
load(reader, errors);
return errors;
}
/**
* Reads and unmarshals all values associated with the registered
* parameters from <code>reader</code>. If any errors are
* encountered, they are added to <code>errors</code>.
*
* @param reader The <code>ParameterReader</code> from which to
* fetch the values; it cannot be null
* @param errors The <code>ErrorList</code> that captures any
* errors while loading; it cannot be null
*/
public final void load(final ParameterReader reader,
final ErrorList errors) {
if (Assert.isEnabled()) {
Assert.exists(reader, ParameterReader.class);
Assert.exists(errors, ErrorList.class);
}
m_map.putAll((Map) m_param.read(reader, errors));
}
/**
* Validates all values associated with the registered parameters.
* Any errors encountered are returned.
*
* @return An <code>ErrorList</code> containing validation errors;
* it cannot be null
*/
public final ErrorList validate() {
final ErrorList errors = new ErrorList();
m_param.validate(m_map, errors);
return errors;
}
/**
* @see ParameterContext#validate(ErrorList)
*/
public final void validate(final ErrorList errors) {
Assert.exists(errors, ErrorList.class);
m_param.validate(m_map, errors);
}
/**
* @see ParameterContext#save(ParameterWriter)
*/
public final void save(ParameterWriter writer) {
m_param.write(writer, m_map);
}
/**
* Loads source data for <code>ParameterInfo</code> objects from
* the file <code>YourClass_parameter.properties</code> next to
* <code>YourClass.class</code>.
*
* <code>YourClass_parameter.properties</code>:
*
* <blockquote><pre>
* yourforum.notification_enabled.title=Flag to enable forum notifications
* yourforum.notification_enabled.purpose=Enables or disables forum notifications
* yourforum.notification_enabled.example=true
* yourforum.notifiaction_enabled.format=true|false
* </pre></blockquote>
*
* @see ParameterInfo
*/
protected final void loadInfo() {
final InputStream in = findInfo(getClass());
try {
m_info.load(in);
} catch (IOException ioe) {
throw new UncheckedWrapperException(ioe);
}
final Iterator params = m_param.iterator();
while (params.hasNext()) {
final Parameter param = (Parameter) params.next();
param.setInfo(new Info(param));
}
}
//
// Private classes and methods
//
private class Info implements ParameterInfo {
private final String m_name;
Info(final Parameter param) {
m_name = param.getName();
}
public final String getTitle() {
return m_info.getProperty(m_name + ".title");
}
public final String getPurpose() {
return m_info.getProperty(m_name + ".purpose");
}
public final String getExample() {
return m_info.getProperty(m_name + ".example");
}
public final String getFormat() {
return m_info.getProperty(m_name + ".format");
}
}
private static InputStream findInfo(final Class klass) {
final List files = new LinkedList();
InputStream in = findInfo(klass, files);
if ( in == null ) {
throw new IllegalStateException
("Could not find any of the following files: " + files);
}
return in;
}
private static InputStream findInfo(final Class klass, final List files) {
if (klass == null) { return null; }
final String name =
klass.getName().replace('.', '/') + "_parameter.properties";
files.add(name);
if ( klass.getClassLoader() == null ) {
return null;
}
final InputStream in = klass.getClassLoader().getResourceAsStream(name);
if (in == null) {
return findInfo(klass.getSuperclass(), files);
} else {
return in;
}
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import org.apache.commons.beanutils.converters.BooleanConverter;
/**
* Subject to change.
*
* A parameter representing a Java <code>Boolean</code>.
*
* @see java.lang.Boolean
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class BooleanParameter extends AbstractParameter {
static {
Converters.set(Boolean.class, new BooleanConverter());
}
public BooleanParameter(final String name) {
super(name, Boolean.class);
}
public BooleanParameter(final String name,
final int multiplicity,
final Object defaalt) {
super(name, multiplicity, defaalt, Boolean.class);
}
}

View File

@ -0,0 +1,266 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import com.arsdigita.util.UncheckedWrapperException;
// import com.arsdigita.util.parameter.ErrorList;
// import com.arsdigita.util.parameter.Parameter;
// import com.arsdigita.util.parameter.ParameterLoader;
// import com.arsdigita.util.parameter.ParameterValue;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Processes an input stream (a set of lines, each containing a comma separated
* list of parameter values) and ....
*
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public final class CSVParameterReader implements ParameterReader {
private final LineNumberReader m_reader;
private final Parameter[] m_params;
private final HashMap m_line;
/**
* Constructor
*
* @param reader: input stream to read values
* @param params: array of parameter objects to store procecced values
*/
public CSVParameterReader(final Reader reader, final Parameter[] params) {
m_reader = new LineNumberReader(reader); // input stream
m_params = params; // array of parameters
m_line = new HashMap(params.length); //
}
/**
* read
*
*
*
* @param param
* @param errors
* @return
*/
public final String read(final Parameter param, final ErrorList errors) {
return (String) m_line.get(param);
}
/*
* May 2009: Obviously a reminiscence from previous versions of code. This class
* is currently used by coreloader only and it does not use the load method
* and it works with load commented out.
*
* Code should be removed after extensive testing.
*
public final ParameterValue load(final Parameter param) {
final ParameterValue value = new ParameterValue();
// XXX this won't work correctly with compound parameters
value.setObject(param.read(this, value.getErrors()));
value.getErrors().check();
return value;
}
*/
/**
* Just a public visible entry point into internalNext, used to process
* an exception if thrown.
*
* @return: boolean true if any values could be processed.
*/
public final boolean next() {
try {
return internalNext();
} catch (IOException ioe) {
throw new UncheckedWrapperException(ioe);
}
}
/**
* Internally used worker method which processes the next() method.
*
* Reads in a line from input stream and asks parseLine to process it. The
* resulting array of strings (each containing a value)
* @return
* @throws java.io.IOException
*/
private boolean internalNext() throws IOException {
final String line = m_reader.readLine();
if (line == null) {
return false;
} else {
final String[] elems = parseLine(line);
// m_params: array of parameters to store the comma separated values
// used to determine the max. number of values which can be processed.
for (int i = 0; i < m_params.length; i++) {
if (i < elems.length) {
// If for the given index into the array of parametes a
// corresponding element in the array of strings exist,
// store it in a hash map (a hash map per line)
m_line.put(m_params[i], elems[i]);
} else {
m_line.put(m_params[i], null);
}
}
return true;
}
}
private static final char ESCAPE = '\\';
private static final char QUOTE = '"';
private static final char SEPARATOR = ',';
/**
* Internal used helper method of method parseLine.
*
* @param c
* @return
*/
private char escape(char c) {
switch (c) {
case 'n':
return '\n';
case 't':
return '\t';
case 'r':
return '\r';
default:
return c;
}
}
/**
* Takes a string and analyses it as a list of comma separated values.
*
* Internally used to store each value found in a new string and add it
* to an array of strings.
*
* @param line: string containing a comma separated list of values
* @return : array of strings, each containing a value of the list
*/
private String[] parseLine(final String line) {
int length = line.length();
// Check here if the last character is an escape character so
// that we don't need to check in the main loop.
if (line.charAt(length - 1) == ESCAPE) {
throw new IllegalArgumentException
(m_reader.getLineNumber() +
": last character is an escape character\n" + line);
}
// The set of parsed fields.
List result = new ArrayList();
// The characters between seperators.
StringBuffer buf = new StringBuffer(length);
// Marks the begining of the field relative to buf,
// -1 indicates the beginning of buf.
int begin = -1;
// Marks the end of the field relative to buf.
int end = 0;
// Indicates whether or not we're in a quoted string.
boolean quote = false;
for (int i = 0; i < length; i++) {
char c = line.charAt(i);
if (quote) {
switch (c) {
case QUOTE:
quote = false;
break;
case ESCAPE:
buf.append(escape(line.charAt(++i)));
break;
default:
buf.append(c);
break;
}
end = buf.length();
} else {
switch (c) {
case SEPARATOR:
result.add(field(buf, begin, end));
buf = new StringBuffer(length);
begin = -1;
end = 0;
break;
case ESCAPE:
if (begin < 0) { begin = buf.length(); }
buf.append(escape(line.charAt(++i)));
end = buf.length();
break;
case QUOTE:
if (begin < 0) { begin = buf.length(); }
quote = true;
end = buf.length();
break;
default:
if (begin < 0 &&
!Character.isWhitespace(c)) {
begin = buf.length();
}
buf.append(c);
if (!Character.isWhitespace(c)) { end = buf.length(); }
break;
}
}
}
if (quote) {
throw new IllegalArgumentException
(m_reader.getLineNumber() + ": unterminated string\n" + line);
} else {
result.add(field(buf, begin, end));
}
String[] fields = new String[result.size()];
result.toArray(fields);
return fields;
}
/**
* internal helper method for method parseLine
*
* @param field
* @param begin
* @param end
* @return
*/
private String field(StringBuffer field, int begin, int end) {
if (begin < 0) {
return field.substring(0, end);
} else {
return field.substring(begin, end);
}
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import org.apache.commons.beanutils.converters.ClassConverter;
import org.apache.log4j.Logger;
/**
* A parameter representing a Java <code>Class</code>.
*
* Subject to change.
*
* @see java.lang.Class
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class ClassParameter extends AbstractParameter {
private static final Logger logger = Logger.getLogger(ClassParameter.class);
static {
logger.debug("Static initalizer starting...");
Converters.set(Class.class, new ClassConverter());
logger.debug("Static initalizer finished.");
}
public ClassParameter(final String name) {
super(name, Class.class);
}
public ClassParameter(final String name,
final int multiplicity,
final Object defaalt) {
super(name, multiplicity, defaalt, Class.class);
}
// value != null
protected Object unmarshal(String value, ErrorList errors) {
Class theClass = null;
try {
theClass = Class.forName(value);
} catch (ClassNotFoundException e) {
errors.add(new ParameterError(this, "No such class: " + value));
}
return theClass;
}
protected String marshal(Object value) {
Class theClass = ((Class) value);
if (theClass == null) {
return null;
} else {
return theClass.getName();
}
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import com.arsdigita.util.Assert;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
/**
* Aggregates a set of <code>ParameterReaders</code> so they may be
* treated as one.
*
* Subject to change.
*
* @see ParameterReader
* @author Rafael H. Schloming &lt;rhs@mit.edu&gt;
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class CompoundParameterReader implements ParameterReader {
private static final Logger s_log = Logger.getLogger
(CompoundParameterReader.class);
private final List m_readers;
/**
* Constructs a new compound parameter reader.
*/
public CompoundParameterReader() {
m_readers = new ArrayList();
}
/**
* Adds <code>reader</code> to the set of component readers.
*
* @param reader The <code>ParameterReader</code> being added; it
* cannot be null
*/
public void add(final ParameterReader reader) {
Assert.exists(reader, ParameterReader.class);
m_readers.add(reader);
}
/**
* @see ParameterReader#read(Parameter,ErrorList)
*/
public String read(final Parameter param, final ErrorList errors) {
for (final Iterator it = m_readers.iterator(); it.hasNext(); ) {
final ParameterReader reader = (ParameterReader) it.next();
final String result = reader.read(param, errors);
if (result != null) {
return result;
}
}
return null;
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import com.arsdigita.util.Assert;
import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import org.apache.commons.beanutils.Converter;
/**
* Subject to change.
*
* Collects together BeanUtils converters for use by the base
* <code>Parameter</code>s.
*
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class Converters {
private static Map s_converters = Collections.synchronizedMap
(new HashMap());
/**
* Gets the <code>Converter</code> registered for
* <code>clacc</code>. This method will fail if no converter is
* found.
*
* @param clacc The <code>Class</code> of the parameter value; it
* cannot be null
* @return A <code>Converter</code> instance; it cannot be null
*/
public static final Converter get(final Class clacc) {
Assert.exists(clacc, Class.class);
final Converter converter = (Converter) s_converters.get(clacc);
Assert.exists(converter, Converter.class);
return converter;
}
/**
* Registers <code>converter</code> for <code>clacc</code>.
*
* @param clacc The <code>Class</code> of the parameter value; it
* cannot be null
* @param converter The <code>Converter</code> to register to
* <code>clacc</code>; it cannot be null
*/
public static final void set(final Class clacc, final Converter converter) {
if (Assert.isEnabled()) {
Assert.exists(clacc, Class.class);
Assert.exists(converter, Converter.class);
}
s_converters.put(clacc, converter);
}
/**
* Converts <code>value</code> using the converter registered for
* <code>clacc</code>.
*
* @param clacc The <code>Class</code> of the parameter value; it
* cannot be null
* @param value The <code>String</code>-encoded value of the
* parameter; it may be null
* @return The Java object conversion for <code>value</code>; it
* may be null
*/
public static final Object convert(final Class clacc, final String value) {
Assert.exists(clacc, Class.class);
return get(clacc).convert(clacc, value);
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import org.apache.oro.text.perl.Perl5Util;
/**
* Subject to change.
*
* A parameter representing an <code>InternetAddress</code>.
*
* @see javax.mail.internet.InternetAddress
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class EmailParameter extends StringParameter {
private static final Perl5Util s_perl = new Perl5Util();
private static final String s_regex =
"/^[^@<>\"\t ]+@[^@<>\".\t]+([.][^@<>\".\n ]+)+$/";
public EmailParameter(final String name) {
super(name);
}
protected Object unmarshal(final String value, final ErrorList errors) {
try {
return new InternetAddress(value);
} catch (AddressException ae) {
errors.add(new ParameterError(this, ae));
return null;
}
}
protected void doValidate(final Object value, final ErrorList errors) {
super.doValidate(value, errors);
final InternetAddress email = (InternetAddress) value;
if (!s_perl.match(s_regex, email.toString())) {
final ParameterError error = new ParameterError
(this, "The value is not a valid email address");
errors.add(error);
}
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import java.util.HashMap;
import org.apache.log4j.Logger;
/**
* Subject to change.
*
* A parameter that maps keys to values and, given a key, marshals or
* unmarshals to the corresponding value.
*
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class EnumerationParameter extends AbstractParameter {
private static final Logger s_log = Logger.getLogger
(EnumerationParameter.class);
private final HashMap m_entries;
private final HashMap m_reverse;
public EnumerationParameter(final String name,
final int multiplicity,
final Object defaalt) {
super(name, multiplicity, defaalt);
m_entries = new HashMap();
m_reverse = new HashMap();
}
public EnumerationParameter(final String name) {
this(name, Parameter.REQUIRED, null);
}
public final void put(final String name, final Object value) {
if (m_entries.containsKey(name)) {
throw new IllegalArgumentException
("name already has a value: " + name);
}
if (m_reverse.containsKey(value)) {
throw new IllegalArgumentException
("value already has a name: " + value);
}
m_entries.put(name, value);
m_reverse.put(value, name);
}
protected Object unmarshal(final String value, final ErrorList errors) {
if (m_entries.containsKey(value)) {
return m_entries.get(value);
} else {
final ParameterError error = new ParameterError
(this, "The value must be one of " + m_entries.keySet());
errors.add(error);
return null;
}
}
protected String marshal(Object value) {
return (String) m_reverse.get(value);
}
}

View File

@ -0,0 +1,156 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import com.arsdigita.util.Assert;
import com.arsdigita.util.UncheckedWrapperException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.log4j.Logger;
/**
* Subject to change.
*
* A collection to store <code>ParameterError</code>s that are
* encountered during parameter reading or validation. This
* collection is used in the lifecycle methods of
* <code>Parameter</code>. It is ordinarily returned to the
* parameter-using code so that it can handle errors.
*
* @see ParameterError
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public final class ErrorList {
private static final Logger s_log = Logger.getLogger(ErrorList.class);
private final ArrayList m_params;
// XXX temporarily package access
final ArrayList m_errors;
/**
* Constructs a new error list.
*/
public ErrorList() {
m_params = new ArrayList();
m_errors = new ArrayList();
}
/**
* Adds <code>error</code> to the error list.
*
* @param error A <code>ParameterError</code> representing a read
* or validation error; it cannot be null
*/
public final void add(final ParameterError error) {
Assert.exists(error, ParameterError.class);
final Parameter param = error.getParameter();
synchronized (m_params) {
if (!m_params.contains(param)) {
m_params.add(param);
}
}
m_errors.add(error);
}
/**
* Gets an iterator over the currently stored errors.
*
* @see ParameterError
* @return An <code>Iterator</code> of
* <code>ParameterError</code>s; it cannot be null
*/
public final Iterator iterator() {
return m_errors.iterator();
}
/**
* Tells whether the error collection is empty or not.
*
* @return <code>true</code> if the collection is empty, otherwise
* <code>false</code>
*/
public final boolean isEmpty() {
return m_errors.isEmpty();
}
/**
* Throws a <code>ParameterException</code> containing the error
* list. This method is for use when the client code wants the
* program to fail via an exception if there are errors.
*
* @throws ParameterException if the error list is not empty
*/
public final void check() throws ParameterException {
if (!isEmpty()) {
final StringWriter writer = new StringWriter();
report(writer);
s_log.error(writer.toString());
throw new ParameterException
("Errors encountered while reading parameters", this);
}
}
/**
* Prints parameter errors to <code>out</code> with formatting
* appropriate to the console.
*
* @param out The <code>Writer</code> to print the errors to
*/
public final void report(final Writer out) {
try {
Assert.exists(out, PrintWriter.class);
final Iterator params = m_params.iterator();
while (params.hasNext()) {
final Parameter param = (Parameter) params.next();
out.write("Parameter " + param.getName() + " has the " +
"following errors:\n");
final Iterator errors = m_errors.iterator();
while (errors.hasNext()) {
final ParameterError error =
(ParameterError) errors.next();
if (error.getParameter().equals(param)) {
out.write("\t" + error.getMessage() + "\n");
}
}
}
out.flush();
} catch (IOException ioe) {
throw new UncheckedWrapperException(ioe);
}
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import java.io.File;
import org.apache.log4j.Logger;
/**
* A Parameter representing a File
*
* @see Parameter
* @see java.io.File
* @author bche
*/
public class FileParameter extends AbstractParameter {
private static final Logger s_log = Logger.getLogger(FileParameter.class);
public FileParameter(final String name) {
super(name, File.class);
}
public Object unmarshal(final String value, final ErrorList errors) {
final String sPath = value;
File file = new File(sPath);
if (file.exists()) {
return file;
} else {
return null;
}
}
public String marshal(final Object value) {
final File file = (File) value;
if (file == null) {
return null;
} else {
return file.getAbsolutePath();
}
}
public void doValidate(final Object value, final ErrorList errors) {
final File file = (File) value;
if (!file.exists()) {
errors.add(
new ParameterError(
this,
"File " + file.getAbsolutePath() + " does not exist"));
}
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import org.apache.commons.beanutils.converters.IntegerConverter;
import org.apache.log4j.Logger;
/**
* A parameter representing a Java <code>Integer</code>.
*
* Subject to change.
*
* @see java.lang.Integer
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class IntegerParameter extends AbstractParameter {
private final static Logger logger = Logger.getLogger(IntegerParameter.class);
static {
logger.debug("Static initalizer starting...");
Converters.set(Integer.class, new IntegerConverter());
logger.debug("Static initalizer finished.");
}
public IntegerParameter(final String name) {
super(name, Integer.class);
}
public IntegerParameter(final String name,
final int multiplicity,
final Object defaalt) {
super(name, multiplicity, defaalt, Integer.class);
}
}

View File

@ -0,0 +1,115 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import com.arsdigita.util.Assert;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
/**
* A parameter that manages a collection of <code>Parameter</code> to
* <code>Object</code> value mappings.
*
* Subject to change.
*
* @see java.util.Map
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class MapParameter extends AbstractParameter {
private final ArrayList m_params;
public MapParameter(final String name,
final int multiplicity,
final Object defaalt) {
super(name, multiplicity, defaalt, String.class);
m_params = new ArrayList();
}
public MapParameter(final String name) {
super(name, String.class);
m_params = new ArrayList();
}
public final void add(final Parameter param) {
Assert.exists(param, Parameter.class);
m_params.add(param);
}
public final boolean contains(final Parameter param) {
Assert.exists(param, Parameter.class);
return m_params.contains(param);
}
public final Iterator iterator() {
return m_params.iterator();
}
protected Object doRead(final ParameterReader reader,
final ErrorList errors) {
final HashMap map = new HashMap();
final Iterator params = m_params.iterator();
while (params.hasNext()) {
final Parameter param = (Parameter) params.next();
final Object value = param.read(reader, errors);
if (value != null) {
map.put(param, value);
}
}
return map;
}
protected void doValidate(final Object value, final ErrorList errors) {
final HashMap map = (HashMap) value;
final Iterator params = m_params.iterator();
while (params.hasNext()) {
final Parameter param = (Parameter) params.next();
if (map.containsKey(param)) {
param.validate(map.get(param), errors);
} else {
param.validate(param.getDefaultValue(), errors);
}
}
}
protected void doWrite(final ParameterWriter writer, final Object value) {
final HashMap map = (HashMap) value;
final Iterator params = m_params.iterator();
while (params.hasNext()) {
final Parameter param = (Parameter) params.next();
if (map.containsKey(param)) {
param.write(writer, map.get(param));
}
}
}
}

View File

@ -0,0 +1,183 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
/**
* Describes a named property that can read, write, and validate its
* own value.
*
* Subject to change.
*
* See the documentation on {@link #read}, {@link #write}, and {@link #validate}
* for details.
* They have the following features as well:
*
* <ul>
* <li>Multiplicity. A parameter can be nullable (0..x) or required
* (1..x) and singular (x..1) or multiple (x..n). The current
* parameter implementation only models nullablel vs. required
* parameters.</li>
*
* <li>Defaulting. A parameter can have a value to fall back on if
* none is set.</li>
*
* <li>Optional metadata. Optional extra "info" can be associated
* with a parameter.</li>
* </ul>
*
* The read and validate phases of a parameter collect errors into a
* list so that calling code can control error handling. This is in
* lieu of throwing exceptions that are not useful in creating
* error-recovery UIs.
*
* In contrast, the write phase of a parameter is expected to complete
* successfully or fail outright.
*
* Parameters are stateless "messages". They do not store their own
* values. Instead, a {@link com.arsdigita.util.parameter.ParameterContext}
* manages a set of parameters and keeps their values.
*
*
* Here's what it typically looks like to use a parameter:
*
* <blockquote><code>
* Properties props = System.getProperties();
* ParameterReader reader = JavaPropertyReader(props);
* ParameterWriter writer = JavaPropertyWriter(props);
* ErrorList errors = new ErrorList();
*
* Object value = param.read(reader, errors);
* errors.check(); // If errors is not empty, fails
*
* param.validate(value, errors);
* errors.check(); // If errors is not empty, fails
*
* // We now have a valid unmarshaled value, so code of actual use can
* // go here.
*
* param.write(writer, value);
* </code></blockquote>
*
* @see com.arsdigita.util.parameter.AbstractParameter
* @see com.arsdigita.util.parameter.ParameterContext
* @author Rafael H. Schloming &lt;rhs@mit.edu&gt;
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public interface Parameter {
/**
* Flag to indicate the parameter value is nullable.
*/
public static final int OPTIONAL = 0;
/**
* Flag to indicate the parameter value cannot be null.
*/
public static final int REQUIRED = 1;
/**
* Tells wether the parameter is nullable or not.
*
* @return true if the parameter cannot be null; false if it can
* be null
*/
boolean isRequired();
/**
* Gets the name of the parameter.
*
* @return The <code>String</code> parameter name; it cannot be
* null
*/
String getName();
/**
* Gets the default value of the parameter. Implementations may
* choose to substitute this value for null.
*
* @return The fallback value; it may be null
*/
Object getDefaultValue();
/**
* Gets metadata associated with the parameter if it is available.
*
* @return The <code>ParameterInfo</code> object; it may be null
*/
ParameterInfo getInfo();
/**
* Sets the optional parameter metadata to <code>info</code>.
*
* @param info The <code>ParameterInfo</code> to associate; it may
* be null
*/
void setInfo(ParameterInfo info);
/**
* Gets the parameter value as a Java object. The value will have
* a specific runtime type and so may be appropriately cast.
*
* Reading typically follows the following procedure:
*
* <ul>
* <li>Read the literal string value associated with the
* parameter from <code>reader</code></li>
*
* <li>Convert the literal string value into an approprite Java
* object</li>
* </ul>
*
* If at any point in the process an error is encountered, it is
* added to <code>errors</code>. Callers of this method will
* typically construct an <code>ErrorList</code> in which to
* collect errors.
*
* @param reader The <code>ParameterReader</code> from which to
* recover a string literal value; it cannot be null
* @param errors The <code>ErrorList</code> in which to collect
* any errors encountered; it cannot be null
* @return The Java object value of the parameter
*/
Object read(ParameterReader reader, ErrorList errors);
/**
* Validates the parameter value, <code>value</code>. Any
* validation errors encountered are added to <code>errors</code>.
*
* @param value The value to validate; this is typically the value
* returned by {@link #read}; it may be null
* @param errors The <code>ErrorList</code> in which to collect
* any errors encountered; it cannot be null
*/
void validate(Object value, ErrorList errors);
/**
* Writes the parameter value as a string literal. The parameter
* marshals the object <code>value</code> to a string and sends it
* to <code>writer</code>.
*
* @param writer The <code>ParameterWriter</code> that will take
* the marshaled value and store it; it cannot be null
* @param value The Java object value of the parameter
*/
void write(ParameterWriter writer, Object value);
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
/**
* A container of parameters.
*
* A parameter context binds together a set of parameters and keeps their values.
*
*
* Subject to change.
*
* @see com.arsdigita.util.parameter.Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public interface ParameterContext {
/**
* Returns all the parameters registered on the parameter context.
*
* @return A <code>Parameter[]</code> of all the parameters; it
* cannot be null
*/
Parameter[] getParameters();
/**
* Gets the unmarshaled value of <code>param</code>. If the
* loaded value is null, <code>param.getDefaultValue()</code> is
* returned.
*
* @param param The named <code>Parameter</code> whose value to
* retrieve; it cannot be null
* @return The unmarshaled Java object value of <code>param</code>
*/
Object get(Parameter param);
/**
* Gets the unmarshaled value of <code>param</code>, returning
* <code>dephalt</code> if <code>param</code>'s value is null.
*
* @param param The <code>Parameter</code> whose value to
* retrieve; it cannot be null
* @param dephalt The fallback default value; it may be null
* @return The unmarshaled Java object value of <code>param</code>
* or <code>dephalt</code> if the former is null
*/
Object get(Parameter param, Object dephalt);
/**
* Sets the value of <code>param</code> to <code>value</code>.
*
* @param param The <code>Parameter</code> whose value to set; it
* cannot be null
* @param value The new value of <code>param</code>; it may be
* null
*/
void set(Parameter param, Object value);
/**
* Reads and unmarshals all values associated with the registered
* parameters from <code>reader</code>. If any errors are
* encountered, they are added to <code>errors</code>.
*
* @param reader The <code>ParameterReader</code> from which to
* fetch the values; it cannot be null
* @param errors The <code>ErrorList</code> that captures any
* errors while loading; it cannot be null
*/
void load(ParameterReader reader, ErrorList errors);
/**
* Marshals and writes all values associated with the registered
* parameters to <code>writer</code>.
*
* @param writer The <code>ParameterWriter</code> to which values
* are written; it cannot be null
*/
void save(ParameterWriter writer);
/**
* Validates all values associated with the registered parameters.
* Any errors encountered are added to <code>errors</code>.
*
* @param errors The <code>ErrorList</code> that captures
* validation errors; it cannot be null
*/
void validate(ErrorList errors);
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import com.arsdigita.util.Assert;
/**
* Subject to change.
*
* Information about an error for a parameter. Parameter implementors
* will add <code>ParameterError</code>s to the passed in
* <code>ErrorList</code> when their parameters encounter error
* conditions.
*
* @see ErrorList
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public final class ParameterError {
private final Parameter m_param;
private final String m_message;
private Throwable m_throwable;
/**
* Constructs a parameter error for <code>param</code>.
*
* @param param The <code>Parameter</code> whose value is in
* error; it cannot be null
* @param message A <code>String</code> description of the error
*/
public ParameterError(final Parameter param,
final String message) {
if (Assert.isEnabled()) {
Assert.exists(param, Parameter.class);
Assert.exists(message, String.class);
}
m_param = param;
m_message = message;
}
/**
* Constructs a parameter error for <code>param</code>, drawing
* its error message from <code>throwable</code>.
*
* @param param The <code>Parameter</code> whose value is in
* error; it cannot be null
* @param throwable The <code>Throwable</code> for the error; it
* cannot be null
*/
public ParameterError(final Parameter param,
final Throwable throwable) {
this(param, throwable.getMessage());
m_throwable = throwable;
}
/**
* Gets the parameter associated with this error.
*
* @return The <code>Parameter</code> in error; it cannot be null
*/
public final Parameter getParameter() {
return m_param;
}
/**
* Gets the message associated with this error.
*
* @return The <code>String</code> message for the error; it
* cannot be null
*/
public final String getMessage() {
// XXX this actually can be null, so need to prevent that
return m_message;
}
/**
* Gets the throwable, if present, that corresponds to the error.
*
* @return The <code>Throwable</code> of this error; it may be
* null
*/
public final Throwable getThrowable() {
return m_throwable;
}
/**
* Returns a string representation of the error suitable for
* debugging.
*
* @return <code>super.toString() + "," + param.getName()</code>
*/
@Override
public String toString() {
return super.toString() + "," + m_param.getName();
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import com.arsdigita.util.Assert;
import java.util.List;
import org.apache.log4j.Logger;
/**
* Subject to change.
*
* An exception to indicate invalid parameter states. This exception should only
* be used when the client code of a parameter opts in to using exceptions
* rather than handling parameter errors itself. See
* {@link com.arsdigita.util.parameter.ErrorList#check()}.
*
* @see com.arsdigita.util.parameter.ErrorList
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public final class ParameterException extends RuntimeException {
private static final Logger s_log = Logger.getLogger(
ParameterException.class);
private static final long serialVersionUID = 1726920836531266365L;
private final ErrorList m_errors;
/**
* Constructs a new parameter exception with the content
* <code>message</code>.
*
* @param message A <code>String</code> describing what's wrong; it cannot
* be null
* @param errors The <code>ErrorList</code> containing the errors that
* prompted this exception; it cannot be null
*/
public ParameterException(final String message, final ErrorList errors) {
super(message);
if (Assert.isEnabled()) {
Assert.exists(message, String.class);
Assert.exists(errors, List.class);
}
m_errors = errors;
}
/**
* Gets the set of errors associated with the exception.
*
* @return The <code>ErrorList</code> of errors; it cannot be null
*/
public final ErrorList getErrors() {
return m_errors;
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
/**
* Subject to change.
*
* Metadata for a parameter that is of use for building documentation
* or user interfaces for parameters. The fields are not required and
* thus the methods of this class may return null.
*
* @see Parameter#setInfo(ParameterInfo)
* @see Parameter#getInfo()
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public interface ParameterInfo {
/**
* Gets the pretty name of the parameter.
*
* @return The <code>String</code> title of the parameter; it may
* be null
*/
String getTitle();
/**
* Gets the parameter's reason for being.
*
* @return The <code>String</code> purpose of the parameter; it
* may be null
*/
String getPurpose();
/**
* Gets an example value for the parameter.
*
* @return A <code>String</code> example value; it may be null
*/
String getExample();
/**
* Gets a format description.
*
* @return A format <code>String</code>; it may be null
*/
String getFormat();
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
/**
* Reads an encoded string value for a parameter from storage. Any
* errors encountered while reading are added to an error list.
* This class is counterpart to <code>ParameterWriter</code>.
*
* Subject to change.
*
* @see Parameter#write(ParameterWriter, Object)
* @see ErrorList
* @see ParameterWriter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public interface ParameterReader {
/**
* Reads an encoded <code>String</code> value for
* <code>param</code> from storage. If there are errors, they are
* added to <code>errors</code>.
*
* @param param The <code>Parameter</code> being read; it cannot
* be null
* @param errors The <code>ErrorList</code> that will collect any
* errors; it cannot be null
* @return The marshaled <code>String</code> value for
* <code>param</code>; it may be null
*/
String read(Parameter param, ErrorList errors);
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
/**
* Subject to change.
*
* Writes encoded parameter values to storage. Implementors define
* the exact nature of the storage.
*
* @see Parameter#write(ParameterWriter,Object)
* @see ParameterReader
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public interface ParameterWriter {
/**
* Writes the marshaled <code>value</code> for parameter
* <code>param</code> to storage.
*
* @param param The <code>Parameter</code> that is being written;
* it cannot be null
* @param value The encoded <code>String</code> value to store for
* <code>param</code>; it may be null
*/
void write(Parameter param, String value);
}

View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URL;
import java.util.Iterator;
import org.apache.log4j.Logger;
import com.arsdigita.util.UncheckedWrapperException;
/**
* A parameter representing a JEE <code>Resource</code> (input stream).
*
* This takes in a path and makes sure that the resource exists either
* as a File or an actual resource. If it does, it returns the
* InputStream for the given Resource. If it does not, and if it is
* required, it logs an error. Otherwise, it returns null.
*
* Development note / CHANGELOG
* Had been deprecated for a while in favour of an URLParameter and a
* application specific resource: protocol extension (c.ad.util.protocol.resource).
* As of version 6.5 reverted to ResourceParameter to avoid non-standard extensions.
*
* @author Justin Ross &lt;jross@redhat.com&gt;
* @author Brett &lt;bprucha@users.sourceforge net&gt;
* @author PBoy &lt;pboy@users.sourceforge net&gt;
* @version $Id$
*/
public class ResourceParameter extends AbstractParameter {
private static final Logger s_log = Logger.getLogger(ResourceParameter.class);
private Object m_default = null;
public ResourceParameter(final String name) {
super(name, InputStream.class);
}
public ResourceParameter(final String name,
final int multiplicity,
final Object defaultValue) {
super(name, multiplicity, defaultValue, InputStream.class);
m_default = defaultValue;
}
/**
* Get default value and return it as InputStream.
*
* Developers note:
* This makes the trick to use Parameter.java interface rsp AbstractParameter
* for other types of parameter as String. If you don't overwrite this
* method, you will always get a casting error, because the parameter
* returns a string instead of the intended object!
*
* @return default value as InputStream
*/
public Object getDefaultValue() {
if(m_default instanceof String) {
ErrorList errors = new ErrorList();
InputStream stream = (InputStream)unmarshal((String)m_default, errors);
if(!errors.isEmpty()) {
String strErrors = "";
for(Iterator i = errors.iterator(); i.hasNext(); ) {
ParameterError pe = (ParameterError)i.next();
strErrors += pe.getMessage() + "\r\n";
}
throw new UncheckedWrapperException(strErrors);
}
return stream;
} else
return m_default;
}
/**
* Unmarshals the encoded string value of the parameter to get the intended
* object type. It tries first to find a file of the specified name in the
* file system. If not successful it uses the classloader to find the file
* in the class path / jar files.
*
* @param value
* @param errors
* @return parameter value as an InputStream
*/
@Override
protected Object unmarshal(String value, final ErrorList errors) {
// NOTE:
// This implementation will never find the file in the file system.
// The name has to be specified relativ to document root. So we must
// precede value with the context path, e.g. using
// c.ad.runtime.CCMResourceManager as soon as it's implementation is
// fixed / stable (when all modifications of the runtime environment
// are done).
File file = new File(value);
if (!file.exists()) {
// it is not a standard file so lets try to see if it
// is a resource
if (value.startsWith("/")) {
value = value.substring(1);
}
ClassLoader cload = Thread.currentThread().getContextClassLoader();
URL url = cload.getResource(value);
InputStream stream = cload.getResourceAsStream(value);
if (stream == null && isRequired()) {
s_log.error(value + " is not a valid file and is required");
final ParameterError error = new ParameterError
(this, "Resource not found");
errors.add(error);
}
return stream;
} else {
try {
return new FileInputStream(file);
} catch (FileNotFoundException ioe) {
// we know the file exists so this should not
// be an issue
s_log.error(value + " is not a valid file and is required", ioe);
errors.add(new ParameterError(this, ioe));
return null;
}
}
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import com.arsdigita.util.Classes;
import com.arsdigita.util.UncheckedWrapperException;
/**
* A parameter representing an instance of a Java class.
*
* Subject to change.
*
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class SingletonParameter extends ClassParameter {
public SingletonParameter(final String name) {
super(name);
}
public SingletonParameter(final String name,
final int multiplicity,
final Object defaalt) {
super(name, multiplicity, defaalt);
}
protected String marshal(Object value) {
return super.marshal(value.getClass());
}
protected Object unmarshal(final String value, final ErrorList errors) {
final Class clacc = (Class) super.unmarshal(value, errors);
if(clacc == null) {
return null;
}
try {
return Classes.newInstance(clacc);
} catch (UncheckedWrapperException uwe) {
errors.add(new ParameterError(this, uwe.getRootCause()));
return null;
}
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
/**
* A parameter representing a Java <code>Class</code> which is checked to be
* an implementation of a required class / interface.
*
* Subject to change.
*
* @see java.lang.Class
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class SpecificClassParameter extends ClassParameter {
private Class m_requiredClass;
/**
* Constructor
* @param name
* @param multiplicity
* @param defaultObj
* @param requiredClass
*/
public SpecificClassParameter(final String name,
final int multiplicity,
final Object defaultObj,
final Class requiredClass) {
super(name, multiplicity, defaultObj);
m_requiredClass = requiredClass;
}
/**
* Unmarshals a string representation of the parameter.
*
* @param value string representation of class, must be value != null
* @param errors
* @return
*/
@Override
protected Object unmarshal(String value, ErrorList errors) {
Class theClass = (Class) super.unmarshal(value,errors);
if (theClass != null) {
if (!m_requiredClass.isAssignableFrom(theClass)) {
errors.add(new ParameterError(this, "class " + value +
" must implement : " +
m_requiredClass.getName()));
}
}
return theClass;
}
}

View File

@ -0,0 +1,109 @@
/*
* Copyright (C) 2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
// import com.arsdigita.util.parameter.StringParameter;
// import com.arsdigita.util.parameter.ErrorList;
import com.arsdigita.util.StringUtils;
/**
* StringArrayParameter
*
* Usage Example:
* <pre>
* private static parameter exampleName ;
* exampleName = new StringArrayParameter(
* "com.arsdigita.package.example_name",
* Parameter.REQUIRED,
* new String[] {"String Example 01","String Example 02"}
* );
* </pre>
*
* @version $Id$
*/
public class StringArrayParameter extends StringParameter {
/**
*
* @param name: String literal
* @param multiplicity Indicator wether required (1) or not (0) (nullable)
* @param defaalt default value
*/
public StringArrayParameter(final String name,
final int multiplicity,
final Object defaalt) {
super(name, multiplicity, defaalt);
}
/**
* Converts a String[] object into a literal representation.
*
* @param value
* @return
*/
@Override
protected String marshal(final Object value) {
if (value == null) {
return null;
} else {
return StringUtils.join((String[])value, ',');
}
}
/**
*
* @param literal
* @param errors
* @return
*/
@Override
protected Object unmarshal(final String literal,
final ErrorList errors) {
final String[] literals = StringUtils.split(literal, ',');
final String[] strings = new String[literals.length];
for (int i = 0; i < literals.length; i++) {
final String elem = literals[i];
strings[i] = (String) super.unmarshal(elem, errors);
if (!errors.isEmpty()) {
break;
}
}
return strings;
}
@Override
protected void doValidate(final Object value,
final ErrorList errors) {
if (value != null) {
final String[] strings = (String[]) value;
for (int i = 0; i < strings.length; i++) {
super.doValidate(strings[i], errors);
if (!errors.isEmpty()) {
break;
}
}
}
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import org.apache.commons.beanutils.converters.StringConverter;
import org.apache.log4j.Logger;
/**
* A parameter representing a Java <code>String</code>.
*
* Subject to change.
*
* @see java.lang.String
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class StringParameter extends AbstractParameter {
private static final Logger logger = Logger.getLogger(StringParameter.class);
static {
logger.debug("Static initalizer starting...");
Converters.set(String.class, new StringConverter());
logger.debug("Static initalizer finished.");
}
public StringParameter(final String name,
final int multiplicity,
final Object defaalt) {
super(name, multiplicity, defaalt, String.class);
}
public StringParameter(final String name) {
super(name, String.class);
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.util.parameter;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Subject to change.
*
* A parameter representing a Java <code>URL</code>.
*
* @see java.net.URL
* @see Parameter
* @author Justin Ross &lt;jross@redhat.com&gt;
* @version $Id$
*/
public class URLParameter extends StringParameter {
public URLParameter(final String name) {
super(name);
}
public URLParameter(final String name,
final int multiplicity,
final Object defaalt) {
super(name, multiplicity, defaalt);
}
protected Object unmarshal(final String value, final ErrorList errors) {
try {
return new URL(value);
} catch (MalformedURLException mue) {
errors.add(new ParameterError(this, mue));
return null;
}
}
}

View File

@ -0,0 +1,609 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.xml;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.log4j.Logger;
import com.arsdigita.util.Assert;
import com.arsdigita.util.UncheckedWrapperException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Attr;
/**
* A wrapper class that implements some functionality of
* <code>org.jdom.Element</code> using <code>org.w3c.dom.Element</code>.
*
* @author Patrick McNeill
* @since ACS 4.5a
* @version $Revision$ $Date$
* @version $Id$
*/
public class Element {
private static final Logger s_log = Logger.getLogger(Element.class.getName());
protected org.w3c.dom.Element m_element;
/* DOM element that is being wrapped */
/**
* owner document
*/
private org.w3c.dom.Document m_doc;
private static ThreadLocal s_localDocument = new ThreadLocal() {
@Override
public Object initialValue() {
try {
DocumentBuilderFactory builder =
DocumentBuilderFactory.newInstance();
builder.setNamespaceAware(true);
return builder.newDocumentBuilder().newDocument();
} catch (ParserConfigurationException e) {
s_log.error(e);
throw new UncheckedWrapperException(
"INTERNAL: Could not create thread local DOM document.",
e);
}
}
};
private static org.w3c.dom.Document getDocument() {
return (org.w3c.dom.Document) s_localDocument.get();
}
// public org.w3c.dom.Document getOwnerDocument() {
// if (null == m_doc) {
// m_doc = (org.w3c.dom.Document) s_localDocument.get();
// }
//
// return m_doc;
// }
// public void importElement(final Element element) {
// element.m_element = (org.w3c.dom.Element) this.m_element
// .getOwnerDocument().importNode(element.m_element,
// true);
// }
public void syncDocs() {
if (m_doc == null) {
m_doc = (org.w3c.dom.Document) s_localDocument.get();
}
if (!m_element.getOwnerDocument().equals(m_doc)) {
m_element = (org.w3c.dom.Element) m_doc.importNode(m_element, true);
}
}
/**
* Protected constructor to set up factories, etc. Does not actually
* create a new element. Used if we are programatically setting the
* m_element field later.
*/
protected Element() {
}
/**
* Creates a new element with the given name and no assigned namespace.
*
* @param name the name of the element
*/
public Element(String name) {
this();
Assert.exists(name, String.class);
m_element = getDocument().createElement(name);
}
/**
* Creates a new element with the given name, and assigns it to the
* namespace defined at <code>uri</code>. The namespace prefix is
* automatically determined.
*
* @param name the name of the element
* @param uri the URI for the namespace definition
*/
public Element(String name, String uri) {
Assert.exists(name, String.class);
Assert.exists(uri, String.class);
m_element = getDocument().createElementNS(uri, name);
}
/**
* Creates a new element and adds it as a child to this
* element. <code>elt.newChildElement("newElt")</code> is
* equivalent to
* <pre>
* Element newElt = new Element("newElt");
* elt.addChild(newElt);
* </pre>
*
* @param name the name of the element
* @return the created child element.
* @pre m_element != null
*/
public Element newChildElement(String name) {
Assert.exists(name, String.class);
if (m_doc == null) {
m_doc = this.m_element.getOwnerDocument();
}
Element result = new Element();
result.m_element = m_doc.createElement(name);
this.m_element.appendChild(result.m_element);
return result;
}
/**
* Creates a new element. Adds it as a child to this element
* element and assigns it to the namespace defined at <code>uri</code>.
* <code>elt.newChildElement("newElt", namespace)</code> is
* equivalent to
* <pre>
* Element newElt = new Element("newElt", namespace);
* elt.addChild(newElt);
* </pre>
*
* @param name the name of the Element
* @param uri the URI for the namespace definition
* @return the created child element.
* @pre m_element != null
*/
public Element newChildElement(String name, String uri) {
Assert.exists(name, String.class);
Assert.exists(uri, String.class);
if (m_doc == null) {
m_doc = this.m_element.getOwnerDocument();
}
Element result = new Element();
result.m_element = m_doc.createElementNS(uri, name);
this.m_element.appendChild(result.m_element);
return result;
}
/**
* Copies the passed in element and all of its children to a new
* Element.
*
* @param copyFrom
* @return
*/
public Element newChildElement(Element copyFrom) {
Assert.exists(copyFrom, Element.class);
if (m_doc == null) {
m_doc = this.m_element.getOwnerDocument();
}
Element copyTo = new Element();
copyTo.m_element = m_doc.createElementNS(copyFrom.m_element.getNamespaceURI(), copyFrom.getName());
this.m_element.appendChild(copyTo.m_element);
newChildElementHelper(copyFrom, copyTo);
return copyTo;
}
/**
* Copies the passed in element and all of its children to a new
* Element using the passed-in name.
*
* @param name
* @param copyFrom
* @return
*/
public Element newChildElement(String name, Element copyFrom) {
if (m_doc == null) {
m_doc = this.m_element.getOwnerDocument();
}
Element copyTo = new Element();
copyTo.m_element = m_doc.createElement(name);
this.m_element.appendChild(copyTo.m_element);
newChildElementHelper(copyFrom, copyTo);
return copyTo;
}
/**
* Copies the passed in element and all of its children to a new
* Element using the passed-in name.
*
* @param name
* @param uri
* @param copyFrom
* @return
*/
public Element newChildElement(String name, String uri, Element copyFrom) {
if (m_doc == null) {
m_doc = this.m_element.getOwnerDocument();
}
Element copyTo = new Element();
copyTo.m_element = m_doc.createElementNS(uri, name);
this.m_element.appendChild(copyTo.m_element);
newChildElementHelper(copyFrom, copyTo);
return copyTo;
}
private void newChildElementHelper(Element copyFrom, Element copyTo) {
copyTo.setText(copyFrom.getText());
NamedNodeMap nnm = copyFrom.m_element.getAttributes();
if (nnm != null) {
for (int i = 0; i < nnm.getLength(); i++) {
Attr attr = (org.w3c.dom.Attr) nnm.item(i);
copyTo.addAttribute(attr.getName(), attr.getValue());
}
}
Iterator iter = copyFrom.getChildren().iterator();
while (iter.hasNext()) {
Element child = (Element) iter.next();
copyTo.newChildElement(child);
}
}
/**
* Adds an attribute to the element.
*
* @param name the name of the attribute
* @param value the value of the attribute
* @return this element.
*/
public Element addAttribute(String name, String value) {
Assert.exists(name, String.class);
m_element.setAttribute(name, value);
return this;
}
public Element addAttribute(String name,
String value,
String ns) {
Assert.exists(name, String.class);
Assert.exists(ns, String.class);
m_element.setAttributeNS(ns, name, value);
return this;
}
/**
* Adds a child element to this element.
*
* @param newContent the new child element
* @return this element.
*/
public Element addContent(Element newContent) {
Assert.exists(newContent, Element.class);
newContent.importInto(m_element.getOwnerDocument());
m_element.appendChild(newContent.getInternalElement());
return this;
}
/**
* Sets the text value of the current element (the part between the
* tags). If the passed in text is null then it is converted to
* the empty string.
*
* @param text the text to include
* @return this element.
*/
public Element setText(String text) {
if (text == null) {
// This converts the null to the empty string because
// org.w3c.dom does not like null and HTML does not
// differentiate between "" and null. The other option
// is to throw the NPE which causes other problems
text = "";
}
org.w3c.dom.Text textElem =
m_element.getOwnerDocument().createTextNode(text);
m_element.appendChild(textElem);
return this;
}
/**
* Returns the concatenation of all the text in all child nodes
* of the current element.
*
* @return
*/
public String getText() {
StringBuilder result = new StringBuilder();
org.w3c.dom.NodeList nl = m_element.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
org.w3c.dom.Node n = nl.item(i);
if (n.getNodeType() == org.w3c.dom.Node.TEXT_NODE) {
result.append(((org.w3c.dom.Text) n).getData());
}
}
return result.toString();
}
public Element setCDATASection(String cdata) {
s_log.debug("Setting CDATA section to '" + cdata + "'.");
if (cdata == null) {
cdata = "";
}
org.w3c.dom.CDATASection cdataSection =
m_element.getOwnerDocument().createCDATASection(cdata);
m_element.appendChild(cdataSection);
return this;
}
public String getCDATASection() {
StringBuilder result = new StringBuilder();
org.w3c.dom.NodeList nl = m_element.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
org.w3c.dom.Node n = nl.item(i);
if (n.getNodeType() == org.w3c.dom.Node.CDATA_SECTION_NODE) {
result.append(((org.w3c.dom.CDATASection) n).getData());
}
}
String str = result.toString();
s_log.debug("Fetched this from CDATA section: " + str);
return str;
}
/**
* Returns a <code>List</code> of all the child elements nested
* directly (one level deep) within this element, as <code>Element</code>
* objects. If this target element has no nested elements, an empty
* <code>List</code> is returned. The returned list is "live", so
* changes to it affect the element's actual contents.
* <p>
*
* This performs no recursion, so elements nested two levels deep would
* have to be obtained with:
* <pre>
* Iterator itr = currentElement.getChildren().iterator();
* while (itr.hasNext()) {
* Element oneLevelDeep = (Element)nestedElements.next();
* List twoLevelsDeep = oneLevelDeep.getChildren();
* // Do something with these children
* }
* </pre>
* @return list of child <code>Element</code> objects for this element.
*/
public java.util.List getChildren() {
java.util.List retval = new java.util.ArrayList();
org.w3c.dom.NodeList nl = m_element.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
org.w3c.dom.Node n = nl.item(i);
if (n instanceof org.w3c.dom.Element) {
Element elt = new Element();
elt.m_element = (org.w3c.dom.Element) n;
retval.add(elt);
}
}
return retval;
}
public java.util.Map getAttributes() {
// Retrieve the attributes of the DOM Element
org.w3c.dom.NamedNodeMap attributeNodeMap =
m_element.getAttributes();
// Create the HashMap that we will return the attributes
// in
java.util.HashMap returnMap = new java.util.HashMap();
// Copy the attribute values in the NamedNodeMap to the
// HashMap
for (int i = 0; i < attributeNodeMap.getLength(); ++i) {
// Get the Node
org.w3c.dom.Node attributeNode = attributeNodeMap.item(i);
// Copy the name and value to the map
returnMap.put(attributeNode.getNodeName(),
attributeNode.getNodeValue());
}
// Return the HashMap
return returnMap;
}
/**
* Retrieves an attribute value by name.
* @param name The name of the attribute to retrieve
* @return The Attr value as a string,
* or the empty string if that attribute does not have a specified
* or default value.
*/
public String getAttribute(String name) {
return m_element.getAttribute(name);
}
public boolean hasAttribute(String name) {
return m_element.hasAttribute(name);
}
public String getName() {
return m_element.getTagName();
}
/**
* Functions to allow this class to interact appropriately with the
* Document class (for example, allows nodes to be moved around,
* and so on).
*
* @return the internal DOM Element.
*/
protected final org.w3c.dom.Element getInternalElement() {
return m_element;
}
/**
* Imports the internal node into another document.
* This could also be done with a combination of getInternalElement
* and a setInternalElement function.
*
* @param doc the org.w3c.dom.Document to import into
*/
protected void importInto(org.w3c.dom.Document doc) {
/*
Exception e = new Exception();
java.io.StringWriter sw = new java.io.StringWriter();
e.printStackTrace(new java.io.PrintWriter(sw));
System.out.println(sw.toString().substring(0, 300));
*/
m_element = (org.w3c.dom.Element) doc.importNode(m_element, true);
}
/**
* Workaround for bug in some versions of Xerces.
* For some reason, importNode doesn't also copy attribute
* values unless you call getValue() on them first. This may
* be fixed in a later version of Xerces. In the meantime,
* calling visitAllAttributes(node) before importNode should
* help.
*
* @param node the org.w3c.dom.Node about to be imported
* @deprecated with no replacement, 1 May 2003
*/
public static void visitAllAttributes(org.w3c.dom.Node node) {
org.w3c.dom.NamedNodeMap nnm = node.getAttributes();
if (nnm != null) {
for (int i = 0; i < nnm.getLength(); i++) {
org.w3c.dom.Attr attr = (org.w3c.dom.Attr) nnm.item(i);
attr.getValue();
}
}
org.w3c.dom.NodeList nl = node.getChildNodes();
if (nl != null) {
for (int i = 0; i < nl.getLength(); i++) {
visitAllAttributes(nl.item(i));
}
}
}
/**
* retrieve an unordered list of strings relating to node tree including
* and below the current element. Strings include element names, attribute names,
* attribute values, text and CData sections
* @return
*/
private List getXMLFragments() {
List unsortedList = new ArrayList();
unsortedList.add(getName());
unsortedList.add(getText());
// CData sections are not included in getChildren()
unsortedList.add(getCDATASection());
Iterator it = getAttributes().entrySet().iterator();
while (it.hasNext()) {
java.util.Map.Entry entry = (java.util.Map.Entry) it.next();
unsortedList.add(entry.getKey());
unsortedList.add(entry.getValue());
}
Iterator childElements = getChildren().iterator();
while (childElements.hasNext()) {
Element el = (Element) childElements.next();
unsortedList.addAll(el.getXMLFragments());
}
return unsortedList;
}
/**
* retrieve a string that is an ordered concatenation of all information describing
* this node and its subnodes, suitable as the basis of a hashCode or equals
* implementation.
* @return
*/
protected String getXMLHashString() {
// attributes and child nodes are retrieved as HashMap and List
// respectively. These make no guarantees about the order of
// iteration, and so we sort here to make sure the same element
// will return the same XMLHash
List sortedList = getXMLFragments();
Collections.sort(sortedList);
StringBuilder xml = new StringBuilder();
Iterator xmlFragments = sortedList.iterator();
while (xmlFragments.hasNext()) {
xml.append(xmlFragments.next());
}
s_log.debug("getXMLHashString: " + xml.toString());
return xml.toString();
}
@Override
public int hashCode() {
Date start = new Date();
String hashString = getXMLHashString();
s_log.debug(
"hashCode: getXMLString took "
+ (new Date().getTime() - start.getTime())
+ " millisecs");
return hashString.hashCode();
}
@Override
public boolean equals(Object other) {
s_log.debug("equals invoked");
Date start = new Date();
if (other == null) {
return false;
}
if (!other.getClass().equals(Element.class)) {
return false;
}
Element otherElement = (Element) other;
String thisXML = getXMLHashString();
String otherXML = otherElement.getXMLHashString();
s_log.debug(
"Equals: getXMLString twice took "
+ (new Date().getTime() - start.getTime())
+ " millisecs");
return thisXML.equals(otherXML);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.xml;
/**
* An interface providing an API for converting an object
* to a string. Thus instead of doing
* <pre>
* Date today = new Date();
* element.addAttribute("today", date.toString());
* </pre>
* we can do:
* <pre>
* Date today = new Date();
* element.addAttribute("today", XML.format(date));
* </pre>
* Or if you require a non-default format:
* <pre>
* Date today = new Date();
* element.addAttribute("today", new DateTimeFormatter.format(today));
* </pre>
*/
public interface Formatter {
String format(Object value);
}

View File

@ -0,0 +1,284 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.xml;
import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.xml.formatters.DateTimeFormatter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.log4j.Logger;
/**
* Provides a set of static helper methods for dealing with XML,
* including file parsing &amp; object -> string serialization
*/
public class XML {
private static final Logger s_log = Logger.getLogger(XML.class);
// private static XMLConfig s_config;
private static final Map s_formatters = new HashMap();
static {
s_log.debug("Static initalizer starting...");
s_formatters.put(Date.class, new DateTimeFormatter());
s_log.debug("Static initalizer finished.");
}
/**
* Constructor. All methods are static, no initialization required.
*/
private XML() {}
/**
* Retrieves the current configuration
public static XMLConfig getConfig() {
if (s_config == null) {
s_config = new XMLConfig();
s_config.load();
}
return s_config;
}
*/
/**
* Registers a formatter for serializing objects of a
* class to a String suitable for XML output.
* @param klass
* @param formatter
*/
public static void registerFormatter(Class klass,
Formatter formatter) {
s_formatters.put(klass, formatter);
}
/**
* Unregisters a formatter against a class.
* @param klass
*/
public static void unregisterFormatter(Class klass) {
s_formatters.remove(klass);
}
/**
* Gets a directly registered formatter for a class.
* @param klass the class to find a formatter for
* @return the formatter, or null if non is registered
*/
public static Formatter getFormatter(Class klass) {
return (Formatter)s_formatters.get(klass);
}
/**
* Looks for the best matching formatter.
*
* @param klass the class to find a formatter for
* @return the formatter, or null if non is registered
*/
public static Formatter findFormatter(Class klass) {
Formatter formatter = null;
while (formatter == null && klass != null) {
formatter = getFormatter(klass);
klass = klass.getSuperclass();
}
return formatter;
}
/**
* Converts an object to a String using the closest
* matching registered Formatter implementation. Looks
* for a formatter registered against the object's
* class first, then its superclass, etc. If no formatter
* is found, uses the toString() method.
*
* @param value
* @return
*/
public static String format(Object value) {
if (value == null) {
return null;
}
if (value instanceof String) {
return (String)value;
}
Formatter formatter = findFormatter(value.getClass());
if (formatter == null) {
if (s_log.isDebugEnabled()) {
s_log.debug("No formatter for " + value.getClass());
}
return value.toString();
}
if (s_log.isDebugEnabled()) {
s_log.debug("Processing " + value.getClass() +
" with " + formatter.getClass());
}
return formatter.format(value);
}
/**
* Processes an XML file with the default SAX Parser, with
* namespace processing, schema validation & DTD validation
* enabled.
*
* @param path the XML file relative to the webapp root
* @param handler the content handler
*/
public static final void parseResource(String path,
DefaultHandler handler) {
if (s_log.isDebugEnabled()) {
s_log.debug("Processing resource " + path +
" with " + handler.getClass());
}
if (path.startsWith("/")) {
path = path.substring(1);
}
ClassLoader cload = Thread.currentThread().getContextClassLoader();
InputStream stream = cload.getResourceAsStream(path);
if (stream == null) {
throw new IllegalArgumentException("no such resource: " + path);
}
parse(stream, handler);
}
/**
* Processes an XML file with the default SAX Parser, with
* namespace processing, schema validation & DTD validation
* enabled.
*
* @param source the xml input stream
* @param handler the content handler
*/
public static final void parse(InputStream source,
DefaultHandler handler) {
if (s_log.isDebugEnabled()) {
s_log.debug("Processing stream " + source +
" with " + handler.getClass());
}
try {
// ToDo (pboy): We should use
// SAXParserFactory.newInstance(String clName, ClassLoader clLoader)
// instead to achieve independence of a JVM wide acceptable
// configuration (affecting all CCM instances which may run in a
// container).
// Requires additional modifications in c.ad.util.xml.XML
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://xml.org/sax/features/namespaces", true);
SAXParser parser = spf.newSAXParser();
parser.parse(source, handler);
} catch (ParserConfigurationException e) {
throw new UncheckedWrapperException("error parsing stream", e);
} catch (SAXException e) {
if (e.getException() != null) {
throw new UncheckedWrapperException("error parsing stream",
e.getException());
} else {
throw new UncheckedWrapperException("error parsing stream", e);
}
} catch (IOException e) {
throw new UncheckedWrapperException("error parsing stream", e);
}
}
/**
* This visitor is called by {@link #traverse(Element, int, XML.Action)}.
**/
public interface Action {
void apply(Element elem, int level);
}
/**
* Prints the skeleton structure of the element to the supplied print
* writer.
* @param element
* @param writer
**/
public static void toSkeleton(final Element element,
final PrintWriter writer) {
XML.traverse(element, 0, new Action() {
@Override
public void apply(Element elem, int level) {
final String padding = " ";
for (int ii=0; ii<level; ii++) {
writer.print(padding);
}
writer.print(elem.getName());
Iterator attrs = elem.getAttributes().keySet().iterator();
while (attrs.hasNext()) {
writer.print(" @");
writer.print((String) attrs.next());
}
writer.println("");
}
});
}
/**
* This is a wrapper for {@link #toSkeleton(Element, PrintWriter)}.
*
* @param element
* @return
**/
public static String toSkeleton(Element element) {
StringWriter writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
XML.toSkeleton(element, pw);
pw.close();
return writer.toString();
}
/**
* Pre-order, depth-first traversal.
*
* @param elem
* @param level
* @param action
**/
public static void traverse(Element elem, int level, Action action) {
action.apply(elem, level);
final Iterator children=elem.getChildren().iterator();
while (children.hasNext()) {
XML.traverse((Element) children.next(), level+1, action);
}
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.xml.formatters;
import com.arsdigita.xml.Formatter;
import java.util.Locale;
import java.util.Date;
import java.text.DateFormat;
/**
* An alternate formatter for java.util.Date objects, outputting the date in
* 'medium' format. The time is omitted.
*
* @author unknown
* @author Sören Bernstein <quasi@quasiweb.de>
*/
public class DateFormatter implements Formatter {
private static DateFormatterConfig m_config;
public static final DateFormatterConfig getConfig() {
if (m_config == null) {
m_config = new DateFormatterConfig();
m_config.load();
}
return m_config;
}
@Override
public String format(Object value) {
Date date = (Date) value;
//Locale locale = GlobalizationHelper.getNegotiatedLocale();
final Locale locale = Locale.getDefault();
DateFormat format = DateFormat
.getDateInstance(DateFormat.MEDIUM, locale);
return format.format(date);
}
}

View File

@ -0,0 +1,21 @@
package com.arsdigita.xml.formatters;
import com.arsdigita.runtime.AbstractConfig;
import com.arsdigita.util.parameter.Parameter;
import com.arsdigita.util.parameter.StringParameter;
public final class DateFormatterConfig extends AbstractConfig {
private final Parameter m_locale;
public DateFormatterConfig() {
m_locale = new StringParameter("waf.xml.formatters.locale", Parameter.OPTIONAL, null);
register(m_locale);
loadInfo();
}
public final String getLocale() {
return (String) get (m_locale);
}
}

View File

@ -0,0 +1,4 @@
waf.xml.formatters.locale.title=Locale language code (see http://ftp.ics.uci.edu/pub/ietf/http/related/iso639.txt)
waf.xml.formatters.locale.purpose=If set will use this rather than the contexts locale. Useful for things that may be formatted differently in other locales, eg dates.
waf.xml.formatters.locale.example=en
waf.xml.formatters.locale.format=[string]

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.xml.formatters;
//import com.arsdigita.globalization.GlobalizationHelper;
import com.arsdigita.xml.Formatter;
import java.util.Locale;
import java.util.Date;
import java.text.DateFormat;
/**
* The default formatter for java.util.Date objects, outputing the date in
* 'medium' format and the time in 'short' format.
*
* @author unknown
* @author Sören Bernstein <quasi@quasiweb.de>
*/
public class DateTimeFormatter implements Formatter {
@Override
public String format(Object value) {
Date date = (Date) value;
//Locale locale = GlobalizationHelper.getNegotiatedLocale();
final Locale locale = Locale.getDefault();
DateFormat format = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.SHORT, locale);
return format.format(date);
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2002-2005 Runtime Collective Ltd. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.arsdigita.xml.formatters;
//import com.arsdigita.kernel.Kernel;
import java.util.Calendar;
import java.util.Date;
/**
* A DateFormatter which displays dates as:
* <br>
* &lt;yearNo&gt; | &lt;monthNo&gt; | &lt;dayOfMonthNo&gt; | &lt;dayOfWeekNo&gt;
* | &lt;hour&gt; | &lt;minute&gt; | &lt;second&gt; | &lt;apm&gt; | &lt;localised date&gt;
* <br>
* the numbers are padded with 0s, so the positions of the fields are always
* 0, 7, 12, 17, 21, 26, 31, 36, 41 (in Java), and 1, 8, 13, 18, 22, 27, 32, 37, 42 (in XSL).
*/
public class FullDateFormatter extends DateFormatter {
public static String SEPARATOR = " | ";
public static String AM = "am";
public static String PM = "pm";
public static char ZERO = '0';
public String format(Object value) {
String parentResult = super.format(value);
// if (!XMLConfig.getConfig().getActivateFullTimeFormatter()) {
// return parentResult;
// }
Date date = (Date) value;
Calendar cal = Calendar.getInstance();
StringBuffer result = new StringBuffer(60);
cal.setTime(date);
append(result, cal.get(Calendar.YEAR));
appendMaybeSmall(result, cal.get(Calendar.MONTH));
appendMaybeSmall(result, cal.get(Calendar.DAY_OF_MONTH));
append(result, cal.get(Calendar.DAY_OF_WEEK));
appendMaybeSmall(result, cal.get(Calendar.HOUR));
appendMaybeSmall(result, cal.get(Calendar.MINUTE));
appendMaybeSmall(result, cal.get(Calendar.SECOND));
switch (cal.get(Calendar.AM_PM)) {
case Calendar.AM: result.append(AM); break;
case Calendar.PM: result.append(PM); break;
}
result.append(SEPARATOR)
.append(parentResult);
return result.toString();
}
public void appendMaybeSmall(StringBuffer sb, int value) {
if (value < 10) {
sb.append(ZERO);
}
append(sb, value);
}
public void append(StringBuffer sb, int value) {
sb.append(value)
.append(SEPARATOR);
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.xml.formatters;
import com.arsdigita.xml.Formatter;
import java.util.Locale;
import java.util.Date;
import java.text.DateFormat;
/**
* An alternate formatter for java.util.Date objects,
* outputing the date in 'medium' format. The time
* is ommitted.
*
* @author unknown
* @author Sören Bernstein <quasi@quasiweb.de>
*/
public class TimeFormatter implements Formatter {
@Override
public String format(Object value) {
Date date = (Date) value;
// Locale locale = GlobalizationHelper.getNegotiatedLocale();
final Locale locale = Locale.getDefault();
DateFormat format = DateFormat.getTimeInstance(DateFormat.SHORT, locale);
return format.format(date);
}
}

View File

@ -33,23 +33,23 @@ public class CcmSessionContext implements Serializable {
private static final long serialVersionUID = 6110177865273823685L; private static final long serialVersionUID = 6110177865273823685L;
private Party currentParty; private Subject currentParty;
private Party effectiveParty; private Subject effectiveParty;
public Party getCurrentParty() { public Subject getCurrentParty() {
return currentParty; return currentParty;
} }
public void setCurrentParty(final Party currentParty) { public void setCurrentParty(final Subject currentParty) {
this.currentParty = currentParty; this.currentParty = currentParty;
this.effectiveParty = currentParty; this.effectiveParty = currentParty;
} }
public Party getEffectiveParty() { public Subject getEffectiveParty() {
return effectiveParty; return effectiveParty;
} }
protected void setEffectiveParty(final Party effectiveParty) { protected void setEffectiveParty(final Subject effectiveParty) {
this.effectiveParty = effectiveParty; this.effectiveParty = effectiveParty;
} }
@ -63,7 +63,7 @@ public class CcmSessionContext implements Serializable {
* @param party The party with which permissions the code is executed. * @param party The party with which permissions the code is executed.
* @param runnable The code to execute. * @param runnable The code to execute.
*/ */
public void sudo(final Party party, final Runnable runnable) { public void sudo(final Subject party, final Runnable runnable) {
//ToDo: Check if current user is permitted to use sudo. //ToDo: Check if current user is permitted to use sudo.
effectiveParty = party; effectiveParty = party;

View File

@ -45,7 +45,7 @@ import javax.xml.bind.annotation.XmlRootElement;
@Entity @Entity
@Table(name = "ccm_groups") @Table(name = "ccm_groups")
@XmlRootElement(name = "user-group", namespace = CORE_XML_NS) @XmlRootElement(name = "user-group", namespace = CORE_XML_NS)
public class Group extends Party implements Serializable { public class Group extends Subject implements Serializable {
private static final long serialVersionUID = -5555063356689597270L; private static final long serialVersionUID = -5555063356689597270L;

View File

@ -61,7 +61,7 @@ public class Permission implements Serializable {
@ManyToOne @ManyToOne
@JoinColumn(name = "grantee_id") @JoinColumn(name = "grantee_id")
private Party grantee; private Subject grantee;
@OneToOne @OneToOne
@JoinColumn(name = "granted_privilege_id") @JoinColumn(name = "granted_privilege_id")
@ -94,11 +94,11 @@ public class Permission implements Serializable {
this.permissionId = permissionId; this.permissionId = permissionId;
} }
public Party getGrantee() { public Subject getGrantee() {
return grantee; return grantee;
} }
protected void setGrantee(final Party grantee) { protected void setGrantee(final Subject grantee) {
this.grantee = grantee; this.grantee = grantee;
} }

View File

@ -28,8 +28,12 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import javax.persistence.CollectionTable; import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection; import javax.persistence.ElementCollection;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
@ -44,16 +48,21 @@ import javax.xml.bind.annotation.XmlRootElement;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@Entity @Entity
@Table(name = "parties") @Table(name = "subjects")
@XmlRootElement(name = "party", namespace = CORE_XML_NS) @XmlRootElement(name = "subject", namespace = CORE_XML_NS)
public class Party extends CcmObject implements Serializable { public class Subject implements Serializable {
private static final long serialVersionUID = 6303836654273293979L; private static final long serialVersionUID = 6303836654273293979L;
@Id
@Column(name = "subject_id")
@GeneratedValue(strategy = GenerationType.AUTO)
private long subjectId;
@ElementCollection @ElementCollection
@CollectionTable(name = "party_email_addresses", @CollectionTable(name = "subject_email_addresses",
joinColumns = { joinColumns = {
@JoinColumn(name = "party_id")}) @JoinColumn(name = "subject_id")})
@Size(min = 1) @Size(min = 1)
@XmlElementWrapper(name = "email-addresses", namespace = CORE_XML_NS) @XmlElementWrapper(name = "email-addresses", namespace = CORE_XML_NS)
@XmlElement(name = "email-address", namespace = CORE_XML_NS) @XmlElement(name = "email-address", namespace = CORE_XML_NS)
@ -66,12 +75,20 @@ public class Party extends CcmObject implements Serializable {
@XmlElement(name = "granted-permission", namespace = CORE_XML_NS) @XmlElement(name = "granted-permission", namespace = CORE_XML_NS)
private List<Permission> grantedPermissions; private List<Permission> grantedPermissions;
public Party() { public Subject() {
super(); super();
grantedPermissions = new ArrayList<>(); grantedPermissions = new ArrayList<>();
} }
public long getSubjectId() {
return subjectId;
}
protected void setSubjectId(final long subjectId) {
this.subjectId = subjectId;
}
public List<EmailAddress> getEmailAddresses() { public List<EmailAddress> getEmailAddresses() {
if (emailAddresses == null) { if (emailAddresses == null) {
return null; return null;
@ -113,24 +130,25 @@ public class Party extends CcmObject implements Serializable {
@Override @Override
public int hashCode() { public int hashCode() {
int hash = super.hashCode(); int hash = 7;
hash = 41 * hash + Objects.hashCode(emailAddresses); hash = 53 * hash + (int) (subjectId ^ (subjectId >>> 32));
hash = 53 * hash + Objects.hashCode(emailAddresses);
return hash; return hash;
} }
@Override @Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {
if (!super.equals(obj)) {
return false;
}
if (obj == null) { if (obj == null) {
return false; return false;
} }
if (!(obj instanceof Party)) { if (!(obj instanceof Subject)) {
return false; return false;
} }
final Party other = (Party) obj; final Subject other = (Subject) obj;
if (subjectId != other.getSubjectId()) {
return false;
}
if (!other.canEqual(this)) { if (!other.canEqual(this)) {
return false; return false;
} }
@ -138,9 +156,24 @@ public class Party extends CcmObject implements Serializable {
return Objects.equals(emailAddresses, other.getEmailAddresses()); return Objects.equals(emailAddresses, other.getEmailAddresses());
} }
@Override
public boolean canEqual(final Object obj) { public boolean canEqual(final Object obj) {
return obj instanceof Party; return obj instanceof Subject;
}
@Override
public final String toString() {
return toString("");
}
public String toString(final String data) {
return String.format("%s{ "
+ "subjectId = %d, "
+ "emailAddresses = %s"
+ "%s}",
super.toString(),
subjectId,
Objects.toString(emailAddresses),
data);
} }
} }

View File

@ -38,6 +38,8 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlElementWrapper;
@ -47,11 +49,17 @@ import javax.xml.bind.annotation.XmlTransient;
/** /**
* The {@code User} entity stores the name and the password of a user along with * The {@code User} entity stores the name and the password of a user along with
* some other informations. * some other informations.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@Entity @Entity
@Table(name = "ccm_users") @Table(name = "ccm_users")
@NamedQueries({
@NamedQuery(name = "findUserByScreenName",
query = "SELECT u FROM User u WHERE u.screenName = :screenname"),
@NamedQuery(name = "findUserByEmail",
query = "SELECT u FROM User u JOIN u.emailAddresses e"
+ "WHERE e.address = :emailAddress")})
@XmlRootElement(name = "user", namespace = CORE_XML_NS) @XmlRootElement(name = "user", namespace = CORE_XML_NS)
//Supressing a few warnings from PMD because they misleading here. //Supressing a few warnings from PMD because they misleading here.
//User is perfectly fine class name, and the complexity is not to high... //User is perfectly fine class name, and the complexity is not to high...
@ -59,7 +67,7 @@ import javax.xml.bind.annotation.XmlTransient;
"PMD.CyclomaticComplexity", "PMD.CyclomaticComplexity",
"PMD.StdCyclomaticComplexity", "PMD.StdCyclomaticComplexity",
"PMD.ModifiedCyclomaticComplexity"}) "PMD.ModifiedCyclomaticComplexity"})
public class User extends Party implements Serializable { public class User extends Subject implements Serializable {
private static final long serialVersionUID = 892038270064849732L; private static final long serialVersionUID = 892038270064849732L;
@ -77,18 +85,18 @@ public class User extends Party implements Serializable {
/** /**
* A user name of the user. Usually an abbreviation of the users real name. * A user name of the user. Usually an abbreviation of the users real name.
* For example a the <em>John Doe</em> might have the scree name * For example a the <em>John Doe</em> might have the scree name
* <code>jdoe</code>. The screen name is used as user name for logins (if * <code>jdoe</code>. The screen name is used as user name for logins (if
* the system if configured so, otherwise the email address of the user is * the system if configured so, otherwise the email address of the user is
* used). * used).
*/ */
@Column(name = "screen_name", length = 255, nullable = false) @Column(name = "screen_name", length = 255, nullable = false, unique = true)
@NotBlank @NotBlank
@XmlElement(name = "screen-name", namespace = CORE_XML_NS) @XmlElement(name = "screen-name", namespace = CORE_XML_NS)
private String screenName; private String screenName;
/** /**
* A user can be banned which means that he or she can't login into the * A user can be banned which means that he or she can't login into the
* system anymore. * system anymore.
*/ */
@Column(name = "banned") @Column(name = "banned")
@ -96,7 +104,8 @@ public class User extends Party implements Serializable {
private boolean banned; private boolean banned;
/** /**
* An alias for the user used in an another system for SSO, for example LDAP. * An alias for the user used in an another system for SSO, for example
* LDAP.
*/ */
@Column(name = "sso_login", length = 512) @Column(name = "sso_login", length = 512)
@XmlElement(name = "sso-login", namespace = CORE_XML_NS) @XmlElement(name = "sso-login", namespace = CORE_XML_NS)
@ -117,25 +126,25 @@ public class User extends Party implements Serializable {
private String salt; private String salt;
/** /**
* The hash algorithm used to hash the password. This allows us * The hash algorithm used to hash the password. This allows us the change
* the change to another, stronger hash algorithm without invalidating * to another, stronger hash algorithm without invalidating existing
* existing accounts. The algorithm to use for new passwords can be * accounts. The algorithm to use for new passwords can be configured by the
* configured by the administrator. * administrator.
* *
*/ */
@Column(name = "hash_algorithm", length = 64) @Column(name = "hash_algorithm", length = 64)
@XmlTransient @XmlTransient
private String hashAlgorithm; private String hashAlgorithm;
/** /**
* Indicates that the user should be forced to change his or her password * Indicates that the user should be forced to change his or her password on
* on the next login. * the next login.
*/ */
@Column(name = "password_reset_required") @Column(name = "password_reset_required")
private boolean passwordResetRequired; private boolean passwordResetRequired;
/** /**
* Question the recover a forgotten password. * Question the recover a forgotten password.
*/ */
@Column(name = "password_question", length = 2048) @Column(name = "password_question", length = 2048)
@XmlElement(name = "password-question", namespace = CORE_XML_NS) @XmlElement(name = "password-question", namespace = CORE_XML_NS)

View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.core;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
/**
* This class provides complex operations on {@link User} objects like updating
* the password. To use this class add an injection point to your class.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class UserManager {
/**
* {@link UserRepository} for interacting with the database. The method
* takes care of hashing the password with random salt.
*
*/
@Inject
private transient UserRepository userRepository;
/**
* Update the password of an user.
*
* @param user The user whose password is to be updated.
* @param password The new password.
*/
public void updatePassword(final User user, final String password) {
try {
final Random random = new Random(System.currentTimeMillis());
final byte[] passwordBytes = password.getBytes("UTF-8");
final byte[] salt = new byte[getSaltLength()];
random.nextBytes(salt);
final byte[] saltedPassword = new byte[passwordBytes.length
+ salt.length];
System.arraycopy(passwordBytes,
0,
saltedPassword,
0,
passwordBytes.length);
System.arraycopy(salt,
0,
saltedPassword,
passwordBytes.length,
salt.length);
final MessageDigest digest = MessageDigest.getInstance(
getHashAlgorithm());
final byte[] hashedBytes = digest.digest(saltedPassword);
final String hashedPassword = new String(hashedBytes, "UTF-8");
user.setPassword(hashedPassword);
userRepository.save(user);
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(String.format(
"Configured hash algorithm '%s 'is not available.",
getHashAlgorithm()), ex);
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException("UTF-8 charset is not supported.");
}
}
/**
* Gets the hash algorithm to use.
*
* ToDo: Make configurable.
*
* @return At the moment SHA-512, will be made configurable.
*/
private String getHashAlgorithm() {
return "SHA-512";
}
/**
* Returns the length for the salt (number of bytes).
*
* ToDo: Make configurable.
*
* @return At the moment 256. Will be made configurable.
*/
private int getSaltLength() {
return 256;
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.core;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.persistence.TypedQuery;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class UserRepository extends AbstractEntityRepository<Long, User> {
@Override
public Class<User> getEntityClass() {
return User.class;
}
@Override
public boolean isNew(final User entity) {
return entity.getSubjectId() == 0;
}
public User findByScreenName(final String screenname) {
final TypedQuery<User> query = getEntityManager().createNamedQuery(
"findUserByScreenName", User.class);
query.setParameter("screenname", screenname);
final List<User> result = query.getResultList();
if (result.isEmpty()) {
return null;
} else if (result.size() == 1) {
return result.get(0);
} else {
throw new MultipleMatchingUserException(String.format(
"Found multipe users identified by screen name '%s'. "
+ "Check your database.",
screenname));
}
}
public User findByEmailAddress(final String emailAddress) {
final TypedQuery<User> query = getEntityManager().createNamedQuery(
"findUserByEmailAddress", User.class);
query.setParameter("emailAddress", emailAddress);
final List<User> result = query.getResultList();
if (result.isEmpty()) {
return null;
} else if(result.size() == 1) {
return result.get(0);
} else {
throw new MultipleMatchingUserException(String.format(
"Found multipe users identified by email address '%s'. "
+ "Check your database.",
emailAddress));
}
}
private class MultipleMatchingUserException extends RuntimeException {
private static final long serialVersionUID = 100237510055701060L;
public MultipleMatchingUserException(final String message) {
super(message);
}
}
}

View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.core.authentication;
import com.arsdigita.kernel.KernelConfig;
import org.libreccm.core.User;
import org.libreccm.core.UserRepository;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import javax.inject.Inject;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.AccountNotFoundException;
import javax.security.auth.login.LoginException;
/**
* Checks a username and a password in the database.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class LocalLoginModule extends PasswordLoginModule {
/**
* {@link UserRepository} instance for getting user accounts from the
* database.
*/
@Inject
private transient UserRepository userRepository;
private transient Subject subject;
@Override
public void initialize(final Subject subject,
final CallbackHandler callbackHandler,
final Map<String, ?> sharedState,
final Map<String, ?> options) {
super.initialize(subject, callbackHandler, sharedState, options);
this.subject = subject;
}
@Override
public boolean commit() throws LoginException {
return true;
}
@Override
public boolean abort() throws LoginException {
return true;
}
@Override
public boolean logout() throws LoginException {
return true;
}
/**
* Checks the provided password against the (hashed) password in the
* database.
*
* @param username The username identifying the user account the verify.
* @param password The password to verify.
*
* @return {@code true} if the password matches the password in the
* database, {@code false} if not or if there is no user account
* identified by the provided user name.
*
* @throws LoginException If an error occurs in the process.
*/
@Override
protected boolean checkPassword(final String username,
final String password)
throws LoginException {
//Depending on the configured user identifier retrieve the user account
//using the screen name or the email address.
final User user;
if (KernelConfig.getConfig().emailIsPrimaryIdentifier()) {
user = userRepository.findByEmailAddress(username);
} else {
user = userRepository.findByScreenName(username);
}
//If no matching user is found report this by throwing an exception.
if (user == null) {
throw new AccountNotFoundException(String.format(
"No user account identified by '%s' found.", username));
}
// Verify the password. The algorithm used for hashing is stored in the
// database so we need to retrieve the correct MessageDigest instance
// first.
try {
final MessageDigest digest = MessageDigest.getInstance(user
.getHashAlgorithm());
final String saltedPassword = String.format("%s%s",
password,
user.getSalt());
final String passwordHash = new String(digest.digest(
saltedPassword.getBytes()));
if (passwordHash.equals(user.getPassword())) {
subject.getPrincipals().add(new SubjectPrincipal(user
.getSubjectId()));
return true;
} else {
return false;
}
} catch (NoSuchAlgorithmException ex) {
throw new LoginException(String.format(
"Failed to validate password because the password stored for "
+ "user '%s' in the database is hashed with algorithm '%s' "
+ "which is not avialable.",
username, user.getHashAlgorithm()));
}
}
}

View File

@ -0,0 +1,117 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.core.authentication;
import org.libreccm.core.CcmSessionContext;
import org.libreccm.core.User;
import org.libreccm.core.UserRepository;
import java.io.IOException;
import java.util.Iterator;
import java.util.Set;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
/**
* Provides methods for authenticating a user and for logging out a user.
*
* Under the hood JAAS is used for authentication.
*
* If a user is authenticated successfully the user object is stored in the
* session scoped bean {@link CcmSessionContext}.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class LoginManager {
/**
* Name of the register login context.
*/
private static final String REGISTER_LOGIN_CONTEXT = "RegisterLoginContext";
@Inject
private transient CcmSessionContext sessionContext;
@Inject
private transient UserRepository userRepository;
public void login(final String username, final String password)
throws LoginException {
final CallbackHandler callbackHandler = new LoginCallbackHandler(
username, password);
final LoginContext loginContext = new LoginContext(
REGISTER_LOGIN_CONTEXT,
callbackHandler);
loginContext.login();
final Subject subject = loginContext.getSubject();
final Set<SubjectPrincipal> principals = subject.getPrincipals(
SubjectPrincipal.class);
if (principals.isEmpty()) {
throw new LoginException("No principal set");
} else {
final Iterator<SubjectPrincipal> iterator = principals.iterator();
final SubjectPrincipal principal = iterator.next();
final User user = userRepository.findById(principal.getSubjectId());
sessionContext.setCurrentParty(user);
}
}
private class LoginCallbackHandler implements CallbackHandler {
private final String username;
private final String password;
public LoginCallbackHandler(final String username,
final String password) {
this.username = username;
this.password = password;
}
@Override
public void handle(final Callback[] callbacks)
throws IOException, UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof NameCallback) {
((NameCallback) callback).setName(username);
} else if (callback instanceof PasswordCallback) {
((PasswordCallback) callback).setPassword(password
.toCharArray());
} else {
throw new UnsupportedCallbackException(callback);
}
}
}
}
}

View File

@ -0,0 +1,213 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.core.authentication;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
/**
* This {@code LoginModule} provides common methods for {@code LoginModule}s
* using a username/password combination to authenticate users. If provides
* common methods. It tries to fetch username and password from shared data
* provided by the calling {@link LoginContext} if possible. Otherwise is
* queries the user using {@link Callback}s. Username and password are stored in
* the shared data for use by other {@code LoginModule}s.
*
* This class in a reworked version of
* {@code org.arsdigita.kernel.security.PasswordLoginModule} developed by Sameer
* Ajmani (according to the JavaDoc). The main differences is that the new
* version uses generics and multi-catch for exceptions. Also the code,
* especially if clauses have been reworked to match the conventions enforced by
* PMD and other style checkers. Also the methods {@code getPassword} and
* {@code getUsername} have been renamed to {@code retrievePassword} and
* {@code retrieveUsername} because this class is not a Java Bean and the values
* are not Java Bean Properties.
*
* This class is abstract. The methods
* {@link #checkPassword(java.lang.String, char[])}, {@link #commit()}, {@link #abort()}
* and {@link #logout()} are left to implement by sub classes.
*
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public abstract class PasswordLoginModule implements LoginModule {
private static final Logger LOGGER = LogManager.getLogger(
PasswordLoginModule.class);
/**
* Key for username in shared data map.
*/
private static final String NAME_KEY = "javax.security.auth.login.name";
/**
* Key for password in shared data map.
*/
private static final String PASSWORD_KEY
= "javax.security.auth.login.password";
/**
* Fields set by the {@link #initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)
* method.
* We only set the fields we use in this class.
*/
private CallbackHandler callbackHandler;
private Map<String, ?> sharedState;
/**
* {@inheritDoc }
*
* @param subject {@inheritDoc }
* @param callbackHandler {@inheritDoc }
* @param sharedState {@inheritDoc }
* @param options {@inheritDoc }
*/
@Override
public void initialize(final Subject subject,
final CallbackHandler callbackHandler,
final Map<String, ?> sharedState,
final Map<String, ?> options) {
LOGGER.debug("Initalizing...");
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
LOGGER.debug("Initalized...");
}
/**
* Implementation of the {@link LoginModule#login()} method. Retrieves the
* username and the password using the {@link #retrieveUsername()} and
* {@link #retrievePassword()} methods and call the
* {@link #checkPassword(java.lang.String, char[])} method.
*
* @return The return value of the
* {@link #checkPassword(java.lang.String, char[])} method.
*
* @throws LoginException If something goes wrong.
*/
@Override
public boolean login() throws LoginException {
LOGGER.debug("Trying to authenticate user...");
return checkPassword(retrieveUsername(), retrievePassword());
}
/**
* {@inheritDoc }
*
* @return {@inheritDoc }
*
* @throws LoginException {@inheritDoc }
*/
@Override
public abstract boolean commit() throws LoginException;
/**
* {@inheritDoc }
*
* @return {@inheritDoc }
*
* @throws LoginException {@inheritDoc }
*/
@Override
public abstract boolean abort() throws LoginException;
/**
* {@inheritDoc }
*
* @return {@inheritDoc }
*
* @throws LoginException {@inheritDoc }
*/
@Override
public abstract boolean logout() throws LoginException;
/**
* Attempts to read username from shared data map; otherwise retreives it
* using a NameCallback.
*
* @return the username.
*
* @throws LoginException if an error occurs.
*/
private String retrieveUsername() throws LoginException {
String username = (String) sharedState.get(NAME_KEY);
if (username == null) {
try {
final NameCallback callback = new NameCallback("Username: ");
callbackHandler.handle(new Callback[]{callback});
username = callback.getName();
} catch (IOException | UnsupportedCallbackException ex) {
throw new LoginException("Could not get Username");
}
}
return username;
}
/**
* Attempts to read password from shared data map; otherwise retreives it
* using a PasswordCallback.
*
* @return the password.
*
* @throws LoginException if an error occurs.
*/
private String retrievePassword() throws LoginException {
String password = (String) sharedState.get(PASSWORD_KEY);
if (password == null) {
try {
final PasswordCallback callback = new PasswordCallback(
"Password: ",
false);
callbackHandler.handle(new Callback[]{callback});
password = new String(callback.getPassword());
} catch (UnsupportedCallbackException | IOException ex) {
throw new LoginException("Could not get password");
}
}
return password;
}
/**
* Checks whether the given username/password combination is valid.
*
* @param username the username to check.
* @param password the password to check.
*
* @return {@code true} if the username/password combination is valid,
* {@code false} to otherwise.
*
* @throws LoginException If an error occurs.
*/
protected abstract boolean checkPassword(String username, String password)
throws LoginException;
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2015 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.core.authentication;
import java.security.Principal;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public final class SubjectPrincipal implements Principal {
private final long subjectId;
public SubjectPrincipal(final long subjectId) {
this.subjectId = subjectId;
}
public long getSubjectId() {
return subjectId;
}
@Override
public String getName() {
return Long.toString(subjectId);
}
@Override
public int hashCode() {
int hash = 5;
hash = 41 * hash + (int) (this.subjectId ^ (this.subjectId >>> 32));
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final SubjectPrincipal other = (SubjectPrincipal) obj;
return this.subjectId == other.getSubjectId();
}
@Override
public String toString() {
return String.format("%s{ "
+ "subjectId = %d"
+ " }",
super.toString(),
subjectId);
}
}

View File

@ -19,7 +19,7 @@
package org.libreccm.messaging; package org.libreccm.messaging;
import org.libreccm.core.CcmObject; import org.libreccm.core.CcmObject;
import org.libreccm.core.Party; import org.libreccm.core.Subject;
import org.libreccm.jpa.utils.MimeTypeConverter; import org.libreccm.jpa.utils.MimeTypeConverter;
import java.io.Serializable; import java.io.Serializable;
@ -56,7 +56,7 @@ public class Message extends CcmObject implements Serializable {
@OneToOne @OneToOne
@JoinColumn(name = "sender_id") @JoinColumn(name = "sender_id")
private Party sender; private Subject sender;
@Column(name = "subject") @Column(name = "subject")
private String subject; private String subject;
@ -82,11 +82,11 @@ public class Message extends CcmObject implements Serializable {
@OneToMany(mappedBy = "message") @OneToMany(mappedBy = "message")
private List<Attachment> attachments; private List<Attachment> attachments;
public Party getSender() { public Subject getSender() {
return sender; return sender;
} }
protected void setSender(final Party sender) { protected void setSender(final Subject sender) {
this.sender = sender; this.sender = sender;
} }

View File

@ -19,7 +19,7 @@
package org.libreccm.notification; package org.libreccm.notification;
import org.libreccm.core.CcmObject; import org.libreccm.core.CcmObject;
import org.libreccm.core.Party; import org.libreccm.core.Subject;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
@ -57,7 +57,7 @@ public class Digest extends CcmObject implements Serializable {
@OneToOne @OneToOne
@JoinColumn(name = "from_party_id") @JoinColumn(name = "from_party_id")
private Party fromParty; private Subject fromParty;
@Column(name = "subject", length = 255, nullable = false) @Column(name = "subject", length = 255, nullable = false)
private String subject; private String subject;
@ -78,11 +78,11 @@ public class Digest extends CcmObject implements Serializable {
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
private Date nextRun; private Date nextRun;
public Party getFromParty() { public Subject getFromParty() {
return fromParty; return fromParty;
} }
public void setFromParty(final Party fromParty) { public void setFromParty(final Subject fromParty) {
this.fromParty = fromParty; this.fromParty = fromParty;
} }

View File

@ -19,7 +19,7 @@
package org.libreccm.notification; package org.libreccm.notification;
import org.libreccm.core.CcmObject; import org.libreccm.core.CcmObject;
import org.libreccm.core.Party; import org.libreccm.core.Subject;
import org.libreccm.messaging.Message; import org.libreccm.messaging.Message;
import java.io.Serializable; import java.io.Serializable;
@ -80,7 +80,7 @@ public class Notification extends CcmObject implements Serializable {
@OneToOne @OneToOne
@JoinColumn(name = "receiver_id") @JoinColumn(name = "receiver_id")
private Party receiver; private Subject receiver;
@OneToOne @OneToOne
@JoinColumn(name = "digest_id") @JoinColumn(name = "digest_id")
@ -119,11 +119,11 @@ public class Notification extends CcmObject implements Serializable {
@Column(name = "expunge_message") @Column(name = "expunge_message")
private boolean expungeMessage; private boolean expungeMessage;
public Party getReceiver() { public Subject getReceiver() {
return receiver; return receiver;
} }
public void setReceiver(final Party receiver) { public void setReceiver(final Subject receiver) {
this.receiver = receiver; this.receiver = receiver;
} }

View File

@ -18,7 +18,7 @@
*/ */
package org.libreccm.notification; package org.libreccm.notification;
import org.libreccm.core.Party; import org.libreccm.core.Subject;
import org.libreccm.messaging.Message; import org.libreccm.messaging.Message;
import java.io.Serializable; import java.io.Serializable;
@ -60,7 +60,7 @@ public class QueueItem implements Serializable {
@OneToOne @OneToOne
@JoinColumn(name = "receiver_id") @JoinColumn(name = "receiver_id")
private Party receiver; private Subject receiver;
@Column(name = "retry_count") @Column(name = "retry_count")
private long retryCount; private long retryCount;
@ -89,11 +89,11 @@ public class QueueItem implements Serializable {
this.queueItemId = queueItemId; this.queueItemId = queueItemId;
} }
public Party getReceiver() { public Subject getReceiver() {
return receiver; return receiver;
} }
public void setReceiver(final Party receiver) { public void setReceiver(final Subject receiver) {
this.receiver = receiver; this.receiver = receiver;
} }

View File

@ -18,7 +18,7 @@
*/ */
package org.libreccm.search.lucene; package org.libreccm.search.lucene;
import org.libreccm.core.Party; import org.libreccm.core.Subject;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
@ -92,7 +92,7 @@ public class Document implements Serializable {
@OneToOne @OneToOne
@JoinColumn(name = "created_by_party_id") @JoinColumn(name = "created_by_party_id")
private Party createdBy; private Subject createdBy;
@Column(name = "last_modified") @Column(name = "last_modified")
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
@ -100,7 +100,7 @@ public class Document implements Serializable {
@OneToOne @OneToOne
@JoinColumn(name = "last_modified_by") @JoinColumn(name = "last_modified_by")
private Party lastModifiedBy; private Subject lastModifiedBy;
@Column(name = "content_section", length = 512) @Column(name = "content_section", length = 512)
private String contentSection; private String contentSection;
@ -213,11 +213,11 @@ public class Document implements Serializable {
} }
} }
public Party getCreatedBy() { public Subject getCreatedBy() {
return createdBy; return createdBy;
} }
public void setCreatedBy(final Party createdBy) { public void setCreatedBy(final Subject createdBy) {
this.createdBy = createdBy; this.createdBy = createdBy;
} }
@ -237,11 +237,11 @@ public class Document implements Serializable {
} }
} }
public Party getLastModifiedBy() { public Subject getLastModifiedBy() {
return lastModifiedBy; return lastModifiedBy;
} }
public void setLastModifiedBy(final Party lastModifiedBy) { public void setLastModifiedBy(final Subject lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy; this.lastModifiedBy = lastModifiedBy;
} }

View File

@ -0,0 +1,44 @@
waf.debug.title=Global debug flag
waf.debug.purpose=Enables or disables WAF debugging
waf.debug.example=true
waf.debug.format=true|false
waf.kernel.data_permission_check_enabled.title=DML permission checking flag
waf.kernel.data_permission_check_enabled.purpose=Enables or disables permissions checks on database writes
waf.kernel.data_permission_check_enabled.example=true
waf.kernel.data_permission_check_enabled.format=true|false
waf.kernel.primary_user_identifier.title=The primary user identification
waf.kernel.primary_user_identifier.purpose=Determines whether email addresses or screen names are used to authenticate users
waf.kernel.primary_user_identifier.example=email
waf.kernel.primary_user_identifier.format=email|screen_name
waf.kernel.remember_login.title=Remember login by default
waf.kernel.remember_login.purpose=Determines whether the "remember login" feature is enabled or disabled by default
waf.kernel.remember_login.example=true
waf.kernel.remember_login.format=true|false
waf.kernel.secure_login.title=Require secure login
waf.kernel.secure_login.purpose=Accept only credentials presented over secure connection
waf.kernel.secure_login.example=true
waf.kernel.secure_login.format=true|false
waf.kernel.sso_login.title=Enable SSO login
waf.kernel.sso_login.purpose=Enable alternative "RegisterSSO" login context.
waf.kernel.sso_login.example=false
waf.kernel.sso_login.format=true|false
waf.kernel.supported_languages.title=Set the supported languages for categorization
waf.kernel.supported_languages.purpose=Set the supported languages for categorization. First entry is the default language
waf.kernel.supported_languages.example=en,de,fr,nl,it,pt,es
waf.kernel.supported_languages.format=[string]
waf.kernel.language_independent_items.title=Allow language independent content items
waf.kernel.language_independent_items.purpose=Allow language independent content items
waf.kernel.language_independent_items.example=false
waf.kernel.language_independent_items.format=true|false
waf.kernel.language_independent_code.title=Select language independent code
waf.kernel.language_independent_code.purpose=Allow language independent code
waf.kernel.language_independent_code.example=--
waf.kernel.language_independent_code.format=[string]

View File

@ -41,7 +41,7 @@ public class EqualsAndHashCodeTest extends EqualsVerifier {
CcmObject.class, CcmObject.class,
EmailAddress.class, EmailAddress.class,
GroupMembership.class, GroupMembership.class,
Party.class, Subject.class,
Permission.class, Permission.class,
PersonName.class, PersonName.class,
Privilege.class, Privilege.class,

View File

@ -41,7 +41,7 @@ public class ToStringTest extends ToStringVerifier {
CcmObject.class, CcmObject.class,
EmailAddress.class, EmailAddress.class,
GroupMembership.class, GroupMembership.class,
Party.class, Subject.class,
Permission.class, Permission.class,
PersonName.class, PersonName.class,
Privilege.class, Privilege.class,