Remove Domain sub-project.

This commit is contained in:
Ben Alex 2006-11-12 21:15:22 +00:00
parent 4c8029d234
commit 5ef0a1a4e6
51 changed files with 1 additions and 3843 deletions

View File

@ -1,5 +0,0 @@
target
.settings
.classpath
.project
.wtpmodules

View File

@ -1,42 +0,0 @@
<!--
* ========================================================================
*
* Copyright 2004, 2005 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ========================================================================
-->
<project
xmlns:j="jelly:core"
xmlns:ant="jelly:ant"
xmlns:util="jelly:util"
xmlns:maven="jelly:maven"
>
<!--
Disabled signing the domain JAR for now because it causes Hibernate issues
if people subclass from the net.sf.acegitech.domain.impl package.
<postGoal name="jar:jar">
<j:if test="${context.getVariable('signature.alias') != null}">
<echo>signature.alias defined; signing JAR(s)...</echo>
<ant:signjar lazy="true" alias="${signature.alias}" storepass="${signature.storepass}" keystore="${signature.keystore}">
<fileset dir="${maven.build.dir}">
<include name="*.jar"/>
</fileset>
</ant:signjar>
</j:if>
</postGoal>
-->
</project>

View File

@ -1,44 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-parent</artifactId>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-domain</artifactId>
<name>Acegi Security System for Spring - Domain Object Support</name>
<dependencies>
<dependency>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-hibernate3</artifactId>
<version>2.0-m2</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,12 +0,0 @@
# $Id$
# Values in this file will be overriden by any values with the same name
# in the user-created build.properties file.
# Compile settings
#
# Java 1.5 is required because we use enums extensively in this subproject
# (main Acegi Security project / parent) is Java 1.3 compatible
#
maven.compile.target=1.5
maven.compile.source=1.5

View File

@ -1,60 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project>
<extend>${basedir}/../project.xml</extend>
<pomVersion>3</pomVersion>
<artifactId>acegi-security-domain</artifactId>
<name>Acegi Security System for Spring - Domain Object Support</name>
<siteDirectory>/home/groups/a/ac/acegisecurity/htdocs/multiproject/acegi-security-domain</siteDirectory>
<repository>
<connection>scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity</connection>
<developerConnection>scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity</developerConnection>
<url>http://svn.sourceforge.net/viewcvs.cgi/acegisecurity/trunk/acegisecurity/domain/</url>
</repository>
<dependencies>
<dependency>
<groupId>hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.0.3</version>
<type>jar</type>
<url>http://www.hibernate.org</url>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.6.1</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security</artifactId>
<version>1.0.3-SNAPSHOT</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-hibernate3</artifactId>
<version>2.0-m2</version>
<type>jar</type>
<url>http://www.springframework.org</url>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>${basedir}/../</directory>
<targetPath>META-INF</targetPath>
<includes>
<include>notice.txt</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>

View File

@ -1,50 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain;
import org.acegisecurity.AcegiSecurityException;
/**
* Abstract superclass for all exceptions related to domain object support subproject.
*
* @author Ben Alex
* @version $Id$
*/
public abstract class DomainException extends AcegiSecurityException {
//~ Constructors ===================================================================================================
/**
* Constructs a <code>DomainException</code> with the specified message and
* root cause.
*
* @param msg the detail message
* @param t the root cause
*/
public DomainException(String msg, Throwable t) {
super(msg, t);
}
/**
* Constructs a <code>DomainException</code> with the specified message and
* no root cause.
*
* @param msg the detail message
*/
public DomainException(String msg) {
super(msg);
}
}

View File

@ -1,47 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain;
import java.io.Serializable;
/**
* An interface that indicates an object is a <i>persistable entity</i>.
*
* <p>
* A persistable entity is any object that is capable of being persisted,
* typically via a {@link org.acegisecurity.domain.dao.Dao} implementation.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface PersistableEntity {
//~ Methods ========================================================================================================
/**
* Provides a common getter for the persistence layer to obtain an identity, irrespective of the actual
* type of identity used.<p>Typically a subclass will delegate to a <code>public SomePrimitiveWrapper
* getId()</code> method. The necessity for the <code>getInternalId()</code> abstract method is solely because
* the persistence layer needs a way of obtaining the identity irrespective of the actual identity implementation
* choice.</p>
* <p>Returning <code>null</code> from this method will indicate the object has never been saved. This
* will likely be relied on by some <code>Dao</code> implementations.</p>
*
* @return the persistence identity of this instance
*/
public abstract Serializable getInternalId();
}

View File

@ -1,173 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.dao;
import org.acegisecurity.domain.PersistableEntity;
import org.springframework.dao.DataAccessException;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* Provides fundamental DAO capabilities for a single concrete {@link
* PersistableEntity}, using JDK 1.5 generics.
*
* <P>
* This interface provides a portable approach to Data Access Object (DAO)
* functionality across various object relational persistance solutions.
* </p>
*
* <p>
* It is not envisioned that this interface will provide <b>all</b> data access
* requirements for applications, however it should provide all of the
* standard create, read, update, delete (CRUD) and finder functions that are
* routinely needed. Specialized subclasses (that provide finer-grained
* functionality) of the <code>Dao</code> interface are encouraged.
* </p>
*
* <P>
* A <code>Dao</code> implementation (or a subclass of <code>Dao</code>) should
* be the sole entry point into the persistance layer of an application. The
* persistence layer should only respond to requests from the services layer.
* The services layer is where all transaction demarcation, security
* authorization, workflow and business logic should take place.
* </p>
*
* <p>
* Each <code>Dao</code> implementation will support one
* <code>PersistableEntity</code> classes only. The supported
* <code>PersistableEntity</code> class must be indicated via the {@link
* #supports(Class)} method.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface Dao<E extends PersistableEntity> {
//~ Methods ========================================================================================================
/**
* Create a new object, with the current {@link PersistableEntity#getInternalId()} value being ignored.
*
* @param value (without the identity property initialized)
*
* @throws DataAccessException DOCUMENT ME!
*/
public void create(E value) throws DataAccessException;
/**
* Delete an object.
*
* @param value the value to delete
*
* @throws DataAccessException DOCUMENT ME!
*/
public void delete(E value) throws DataAccessException;
/**
* Return all persistent instances, including subclasses.
*
* @return all persistence instances (an empty <code>List</code> will be returned if no matches are found)
*
* @throws DataAccessException DOCUMENT ME!
*/
public List<E> findAll() throws DataAccessException;
/**
* Find a <code>List</code> of <code>PersistableEntity</code>s, searched by their identifiers.
*
* @param ids collection of identifiers to locate
*
* @return the values with those identifiers (an empty <code>List</code> will be returned if no matches are found)
*
* @throws DataAccessException DOCUMENT ME!
*/
public List<E> findId(Collection<Serializable> ids)
throws DataAccessException;
/**
* Load a persistent instance by its identifier, although some properties may be lazy loaded depending on
* the underlying DAO implementation and/or persistence engine mapping document.
*
* @param id the identifier of the persistent instance desired to be retrieved
*
* @return the request item, or <code>null</code> if not found
*
* @throws DataAccessException DOCUMENT ME!
*/
public E readId(Serializable id) throws DataAccessException;
/**
* Find persistent instances with properties matching those of the passed <code>PersistableEntity</code>.<P>Persistent
* instances are matched on the basis of query by example. Properties whose value is <code>null</code>, empty
* <code>String</code>s, and any <code>Collection</code>s are ignored in the query by example evaluation.</p>
*
* @param value parameters to filter on (the class of this object will be added to the filter)
* @param firstElement the first result (start at zero to obtain all results)
* @param maxElements the maximum number of results desired for this page of the result set
* @param orderByAsc the property name of the <code>PersistableEntity</code> that should be used to order the
* results
*
* @return the requested page of the result list (a properly formed <code>PaginatedList</code> is returned if no
* results match)
*
* @throws DataAccessException DOCUMENT ME!
*/
public PaginatedList<E> scroll(E value, int firstElement, int maxElements, String orderByAsc)
throws DataAccessException;
/**
* Find persistent instances with properties matching those of the passed <code>PersistableEntity</code>,
* ignoring the class of the passed <code>PersistableEntity</code> (useful if you pass a superclass, as you want
* to find all subclass instances which match).
*
* @param value parameters to filter on (the class of this object will NOT be added to the filter)
* @param firstElement the first result (start at zero to obtain all results)
* @param maxElements the maximum number of results desired for this page of the result set
* @param orderByAsc the property name of the <code>PersistableEntity</code> that should be used to order the
* results
*
* @return the requested page of the result list (a properly formed <code>PaginatedList</code> is returned if no
* results match)
*
* @throws DataAccessException DOCUMENT ME!
*/
public PaginatedList<E> scrollWithSubclasses(E value, int firstElement, int maxElements, String orderByAsc)
throws DataAccessException;
/**
* Indicates whether the DAO instance provides persistence services for the specified class.
*
* @param clazz to test, which should be an implementation of <code>PersistableEntity</code>
*
* @return <code>true</code> or <code>false</code>, indicating whether or not the passed class is supported by this
* DAO instance
*/
public boolean supports(Class clazz);
/**
* Update an object.
*
* @param value to update, with the <code>PersistableEntity</code> having a non-<code>null</code> identifier
*
* @throws DataAccessException DOCUMENT ME!
*/
public void update(E value) throws DataAccessException;
}

View File

@ -1,59 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.dao;
/**
* <code>InheritableThreadLocal</code> which indicates whether a {@link Dao} implementation should be forced to
* return a detached instance.<p>A detached instance is one which is no longer associated with the ORM mapper and
* changes will therefore not be transparently persisted to the database.</p>
* <p>Not all <code>Dao</code> implementations support the concept of detached instances.</p>
*
* @author Ben Alex
* @version $Id$
*
* @see java.lang.InheritableThreadLocal
*/
public class DetachmentContextHolder {
//~ Static fields/initializers =====================================================================================
private static InheritableThreadLocal<Boolean> contextHolder = new InheritableThreadLocal<Boolean>();
//~ Methods ========================================================================================================
/**
* Returns the boolean value detachment policy which has been set for the current thread (defaults to
* false).
*
* @return DOCUMENT ME!
*/
public static boolean isForceReturnOfDetachedInstances() {
if (contextHolder.get() == null) {
contextHolder.set(Boolean.FALSE);
}
return contextHolder.get().booleanValue();
}
/**
* Sets whether or not detached domain object instances should be returned within the current thread of
* execution.
*
* @param alwaysReturnDetached if true then detached instances should be returned.
*/
public static void setForceReturnOfDetachedInstances(boolean alwaysReturnDetached) {
contextHolder.set(new Boolean(alwaysReturnDetached));
}
}

View File

@ -1,44 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.dao;
import org.acegisecurity.domain.PersistableEntity;
/**
* Indicates an implementation capable of evicting {@link
* org.acegisecurity.domain.PersistableEntity}s.
*
* <p>
* Structured as a separate interface (rather than a subclass of
* <code>Dao</code>), as it is not required for all persistence strategies.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface EvictionCapable {
//~ Methods ========================================================================================================
/**
* Removes the indicated persistent instance from the DAO's internal map/session.<p>If the passed object
* does not exist in the internal map/session, the invocation has no effect.</p>
* <p>May throw an exception if the implementation so desires.</p>
*
* @param entity to remove from the internal map/session
*/
public void evict(PersistableEntity entity);
}

View File

@ -1,127 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.dao;
import org.acegisecurity.domain.PersistableEntity;
import org.springframework.util.Assert;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
/**
* Convenience methods that support eviction of <code>PersistableEntity</code>s from those objects that implement
* {@link EvictionCapable}.
*
* @author Ben Alex
* @version $Id$
*/
public class EvictionUtils {
//~ Methods ========================================================================================================
/**
* Evicts the <code>PersistableEntity</code> using the passed <code>Object</code> (provided that the passed
* <code>Object</code> implements <code>EvictionCapable</code>).
*
* @param daoOrServices the potential source for <code>EvictionCapable</code> services (never <code>null</code>)
* @param entity to evict (can be <code>null</code>)
*/
public static void evictIfRequired(Object daoOrServices, PersistableEntity entity) {
EvictionCapable evictor = getEvictionCapable(daoOrServices);
if ((evictor != null) && (entity != null)) {
evictor.evict(entity);
}
}
/**
* Evicts each <code>PersistableEntity</code> element of the passed <code>Collection</code> using the
* passed <code>Object</code> (provided that the passed <code>Object</code> implements
* <code>EvictionCapable</code>).
*
* @param daoOrServices the potential source for <code>EvictionCapable</code> services (never <code>null</code>)
* @param collection whose members to evict (never <code>null</code>)
*/
public static void evictIfRequired(Object daoOrServices, Collection<?extends Object> collection) {
Assert.notNull(collection, "Cannot evict a null Collection");
if (getEvictionCapable(daoOrServices) == null) {
// save expense of iterating collection
return;
}
Iterator<?extends Object> iter = collection.iterator();
while (iter.hasNext()) {
Object obj = iter.next();
if (obj instanceof PersistableEntity) {
evictIfRequired(daoOrServices, (PersistableEntity) obj);
}
}
}
/**
* Evicts the <code>PersistableEntity</code> using the passed <code>Object</code> (provided that the passed
* <code>Object</code> implements <code>EvictionCapable</code>), along with expressly evicting every
* <code>PersistableEntity</code> returned by the <code>PersistableEntity</code>'s getters.
*
* @param daoOrServices the potential source for <code>EvictionCapable</code> services (never <code>null</code>)
* @param entity to evict includnig its getter results (can be <code>null</code>)
*/
public static void evictPopulatedIfRequired(Object daoOrServices, PersistableEntity entity) {
EvictionCapable evictor = getEvictionCapable(daoOrServices);
if ((evictor != null) && (entity != null)) {
evictor.evict(entity);
Method[] methods = entity.getClass().getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().startsWith("get") && (methods[i].getParameterTypes().length == 0)) {
try {
Object result = methods[i].invoke(entity, new Object[] {});
if (result instanceof PersistableEntity) {
evictor.evict((PersistableEntity) result);
}
} catch (Exception ignored) {}
}
}
}
}
/**
* Obtain the <code>EvictionCapable</code> from the passed argument, or <code>null</code>.
*
* @param daoOrServices to check if provides eviction services
*
* @return the <code>EvictionCapable</code> object or <code>null</code> if the object does not provide eviction
* services
*/
private static EvictionCapable getEvictionCapable(Object daoOrServices) {
Assert.notNull(daoOrServices, "Cannot evict if the object that may provide EvictionCapable is null");
if (daoOrServices instanceof EvictionCapable) {
return (EvictionCapable) daoOrServices;
} else {
return null;
}
}
}

View File

@ -1,81 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.dao;
/**
* Indicates an implementation capable of initializing an object, such that
* any lazy loading is guaranteed to have been completed.
*
* <p>
* Structured as a separate interface (rather than a subclass of
* <code>Dao</code>), as it is not required for all persistence strategies.
* </p>
*
* <p>In general the recommended approach to lazy initialization is as follows:
*
* <ul>
*
* <li>Do not use OpenSessionInView. You can use it if you like, but you'll have
* less difficulty in the long-run if you plan your use cases and adopt the other
* recommendations below.</li>
*
* <li>Set your mapping documents to use lazy initialization where possible. Only
* mark an association as eager loaded if <b>every</b> single use case requires it
* and you are happy with this eager loading being reflected in a mapping document
* instead of Java code.</li>
*
* <li>Subclass the <code>Dao</code> implementation and add use case specific finder/read
* methods that will use the persistence engine's eager loading capabilities. <b>Generally
* this approach will deliver the best overall application performance</b>, as you will
* (i) only be eager loading if and when required and (ii) you are directly using the
* persistence engine capabilities to do so. It also places the eager loading management
* in the <code>Dao</code>, which is an ideal location to standardise it.</li>
*
* <li>If you would prefer to achieve persistence engine independence and/or reduce
* the number of <code>Dao</code> subclasses that exist in your application, you may
* prefer to modify your services layer so that it uses the <code>InitializationCapable</code>
* interface. However, this interface should be used judiciously given that it does
* not allow the persistence engine to optimise eager loading for given use cases
* and (probably) will lead to a mixture of places where fetching logic can be obtained.</li>
*
* <p>Generally your best strategy is subclassing the <code>Dao</code>. It means the
* most code, but it's also by far the most efficient and offers flexibility to further
* fine-tune specific use cases. Whichever way you go, try to be consistent throughout
* your application (this will ease your future migration and troubleshooting needs).
*
* @author Ben Alex
* @version $Id$
*/
public interface InitializationCapable {
//~ Methods ========================================================================================================
/**
* Initializes the indicated object.<p>May throw an exception if the implementation so desires.</p>
*
* @param entity to initialize
*/
public void initialize(Object entity);
/**
* Indicaets whether the passed object is initialized or not.
*
* @param entity to determine if initialized
*
* @return <code>true</code> if initialized, <code>false</code> is uninitialized or the initialization status is
* unknown
*/
public boolean isInitialized(Object entity);
}

View File

@ -1,66 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.dao;
import org.springframework.util.Assert;
/**
* Convenience methods that support initialization of lazily loaded collections and associations using DAOs and
* other objects that implement {@link org.acegisecurity.domain.dao.InitializationCapable}.
*
* @author Ben Alex
* @version $Id$
*/
public class InitializationUtils {
//~ Methods ========================================================================================================
/**
* Initializes the passed entity using the passed DAO or services layer <code>Object</code> (provided that
* the passed <code>Object</code> implements <code>InitializationCapable</code>).
*
* @param daoOrServices the potential source for <code>InitializationCapable</code> services (never
* <code>null</code>)
* @param entity to evict (can be <code>null</code>)
*/
public static void initializeIfRequired(Object daoOrServices, Object entity) {
Assert.notNull(daoOrServices);
if (daoOrServices instanceof InitializationCapable) {
((InitializationCapable) daoOrServices).initialize(entity);
}
}
/**
* Indicates whether the passed entity has been initialized, by delegating to the passed daoOrServices
* (provided that the passed daoOrServices implements <code>InitializationCapable</code>.
*
* @param daoOrServices DOCUMENT ME!
* @param entity to determine whether initialized or not
*
* @return <code>true</code> if initialized, <code>false</code> if it is uninitialized or the passed daoOrServices
* does not provide initialization querying support
*/
public static boolean isInitialized(Object daoOrServices, Object entity) {
Assert.notNull(daoOrServices);
if (daoOrServices instanceof InitializationCapable) {
return ((InitializationCapable) daoOrServices).isInitialized(entity);
}
return false;
}
}

View File

@ -1,519 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.dao;
import org.acegisecurity.domain.PersistableEntity;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Vector;
/**
* <p>JDK1.5 compatible paginated <code>List</code>.</p>
* <p>Elements in the internal <code>List</code> (see {@link #getList()} represent only part of a larger
* resultset.</p>
* <p>Note that firstElement starts at zero. Any attempt to access other than the current page will cause an
* error.</p>
* <p>This is a read only implementation and many of the <code>List</code> methods are not implemented.</p>
*
* @author Carlos Sanchez
* @author Ben Alex
* @version $Id$
*
* @param <E> DOCUMENT ME!
*/
public class PaginatedList<E extends PersistableEntity> implements List<E> {
//~ Instance fields ================================================================================================
private List<E> list;
protected final transient Log logger = LogFactory.getLog(getClass());
private int firstElement;
private int maxElements;
private int size;
//~ Constructors ===================================================================================================
// TODO: Consider removing this constructor
public PaginatedList() {}
/**
* Used to construct a <code>PaginatedList</code> which contains only the
* given entity.
*
* @param entity the entity to include (can be <code>null</code>, which
* indicates an empty <code>PaginatedList</code> should be created)
*/
public PaginatedList(E entity) {
if (entity == null) {
this.list = new Vector<E>();
this.firstElement = 0;
this.maxElements = Integer.MAX_VALUE;
this.size = 0;
} else {
List<E> myList = new Vector<E>();
myList.add(entity);
this.list = myList;
this.firstElement = 0;
this.maxElements = Integer.MAX_VALUE;
this.size = 1;
}
}
public PaginatedList(List<E> list, int firstElement, int maxElements, int size) {
this.list = list;
this.firstElement = firstElement;
this.maxElements = maxElements;
this.size = size;
}
//~ Methods ========================================================================================================
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
* @param arg1 DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.List#add(int, java.lang.Object)
*/
public void add(int arg0, E arg1) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.Collection#add(java.lang.Object)
*/
public boolean add(E arg0) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.Collection#addAll(java.util.Collection)
*/
public boolean addAll(Collection<?extends E> arg0) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
* @param arg1 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.List#addAll(int, java.util.Collection)
*/
public boolean addAll(int arg0, Collection<?extends E> arg1) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @throws UnsupportedOperationException
*
* @see java.util.Collection#clear()
*/
public void clear() {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.Collection#contains(java.lang.Object)
*/
public boolean contains(Object arg0) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.Collection#containsAll(java.util.Collection)
*/
public boolean containsAll(Collection<?> arg0) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @see java.util.List#get(int)
*/
public E get(int arg0) {
return list.get(arg0);
}
/**
* First element of this page, starting at zero.
*
* @return
*/
public int getFirstElement() {
return firstElement;
}
/**
* Calculate the last page number, starting at 0
*
* @return
*/
public int getLastPageNumber() {
return (size() - 1) / getMaxElements();
}
/**
* Get list with the elements of this page.
*
* @return this page of the results
*/
public List<E> getList() {
return list;
}
/**
* Max number of elements in the page
*
* @return
*/
public int getMaxElements() {
return maxElements;
}
/**
* Calculate the page number, starting at 0
*
* @return
*/
public int getPageNumber() {
return getFirstElement() / getMaxElements();
}
/**
* Number of elements in this page
*
* @return
*/
public int getPageSize() {
return list.size();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.List#indexOf(java.lang.Object)
*/
public int indexOf(Object arg0) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.Collection#isEmpty()
*/
public boolean isEmpty() {
throw new UnsupportedOperationException();
}
public Iterator<E> iterator() {
return new PaginatedListIterator();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.List#lastIndexOf(java.lang.Object)
*/
public int lastIndexOf(Object arg0) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.List#listIterator()
*/
public ListIterator<E> listIterator() {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.List#listIterator(int)
*/
public ListIterator<E> listIterator(int arg0) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.List#remove(int)
*/
public E remove(int arg0) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.Collection#remove(java.lang.Object)
*/
public boolean remove(Object arg0) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.Collection#removeAll(java.util.Collection)
*/
public boolean removeAll(Collection arg0) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.Collection#retainAll(java.util.Collection)
*/
public boolean retainAll(Collection<?> arg0) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
* @param arg1 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.List#set(int, java.lang.Object)
*/
public E set(int arg0, E arg1) {
throw new UnsupportedOperationException();
}
public void setFirstElement(int firstElement) {
this.firstElement = firstElement;
}
public void setList(List<E> list) {
this.list = list;
}
public void setMaxElements(int maxElements) {
this.maxElements = maxElements;
}
/**
* Set the number of elements in all the pages
*
* @param size DOCUMENT ME!
*/
public void setSize(int size) {
this.size = size;
}
/**
* Number of elements in all the pages
*
* @see java.util.Collection#size()
*/
public int size() {
return size;
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
* @param arg1 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.List#subList(int, int)
*/
public List<E> subList(int arg0, int arg1) {
throw new UnsupportedOperationException();
}
public Object[] toArray() {
return list.toArray();
}
public <T> T[] toArray(T[] arg0) {
if (logger.isDebugEnabled()) {
logger.debug("List size when convert to array " + list.toArray().length);
}
return list.toArray(arg0);
}
//~ Inner Classes ==================================================================================================
private class PaginatedListIterator implements Iterator<E> {
private Iterator<E> iterator;
private int i = 0;
/**
*
* @see java.util.Iterator#hasNext()
*/
public boolean hasNext() {
return i < size();
}
/**
* This method follows the rules of Iterator.next() except that it returns null when requesting an
* element that it's not in the current page.
*
* @see java.util.Iterator#next()
*/
public E next() {
if (i == getFirstElement()) {
iterator = getList().iterator();
}
if ((i >= getFirstElement()) && (i < (getFirstElement() + getMaxElements()))) {
i++;
return iterator.next();
}
if (hasNext()) {
i++;
return null;
} else {
throw new NoSuchElementException();
}
}
/**
* Unsupported operation
*
* @throws UnsupportedOperationException
*
* @see java.util.Iterator#remove()
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
}

View File

@ -1,6 +0,0 @@
<html>
<body>
<p>Provides the base of a data access object (DAO) persistence layer.</p>
</body>
</html>

View File

@ -1,269 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.hibernate;
import org.acegisecurity.domain.PersistableEntity;
import org.acegisecurity.domain.dao.Dao;
import org.acegisecurity.domain.dao.PaginatedList;
import org.acegisecurity.domain.util.GenericsUtils;
import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.type.Type;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* Generics supporting {@link Dao} implementation that uses Hibernate 3 for persistence.
*
* @author Ben Alex
* @author Matthew Porter
* @version $Id$
*
* @param <E> DOCUMENT ME!
*/
public class DaoHibernate<E extends PersistableEntity> extends HibernateDaoSupport implements Dao<E> {
//~ Instance fields ================================================================================================
/** The class that this instance provides services for */
private Class supportsClass;
//~ Constructors ===================================================================================================
public DaoHibernate(SessionFactory sessionFactory) {
Assert.notNull(sessionFactory, "Non-null Hibernate SessionFactory must be expressed as a constructor argument");
super.setSessionFactory(sessionFactory);
this.supportsClass = GenericsUtils.getGeneric(getClass());
Assert.notNull(this.supportsClass, "Could not determine the generics type");
}
//~ Methods ========================================================================================================
public void create(E value) {
Assert.notNull(value);
super.getHibernateTemplate().save(value);
}
public void delete(E value) {
Assert.notNull(value);
super.getHibernateTemplate().delete(value);
}
@SuppressWarnings("unchecked")
public List<E> findAll() {
return super.getHibernateTemplate().loadAll(supportsClass);
}
@SuppressWarnings("unchecked")
public List<E> findId(Collection<Serializable> ids) {
Assert.notNull(ids, "Collection of IDs cannot be null");
Assert.notEmpty(ids, "There must be some values in the Collection list");
return (List) super.getHibernateTemplate().execute(getFindByIdCallback(ids));
}
/**
* Provides a <code>HibernateCallback</code> that will load a list of objects by a <code>Collection</code>
* of identities.
*
* @param ids collection of identities to be loaded
*
* @return a <code>List</code> containing the matching objects
*/
private HibernateCallback getFindByIdCallback(final Collection<Serializable> ids) {
return new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException {
Criteria criteria = session.createCriteria(supportsClass);
ClassMetadata classMetadata = getSessionFactory().getClassMetadata(supportsClass);
String idPropertyName = classMetadata.getIdentifierPropertyName();
criteria.add(Expression.in(idPropertyName, ids));
return criteria.list();
}
};
}
/**
* Get a new <code>HibernateCallback</code> for finding objects by a bean property values, paginating the
* results. Properties with null values and collections and empty Strings are ignored, as is any property with the
* "version" name. If the property is mapped as String find a partial match, otherwise find by exact match.
*
* @param whichClass the class (and subclasses) which results will be limited to including
* @param bean bean with the values of the parameters
* @param firstElement the first result, numbered from 0
* @param count the maximum number of results
* @param order DOCUMENT ME!
*
* @return a PaginatedList containing the requested objects
*/
private HibernateCallback getFindByValueCallback(final Class whichClass, final Object bean, final int firstElement,
final int count, final Order order) {
return new HibernateCallback() {
@SuppressWarnings("unchecked")
public Object doInHibernate(Session session)
throws HibernateException {
int paramCount = 0;
StringBuffer queryString = new StringBuffer("from ").append(bean.getClass().getName())
.append(" as queryTarget");
ClassMetadata classMetadata = getSessionFactory().getClassMetadata(bean.getClass());
Assert.notNull(classMetadata,
"ClassMetadata for " + bean.getClass()
+ " unavailable from Hibernate - have you mapped this class against the SessionFactory?");
/* get persistent properties */
Type[] propertyTypes = classMetadata.getPropertyTypes();
String[] propertyNames = classMetadata.getPropertyNames();
/* for each persistent property of the bean */
for (int i = 0; i < propertyNames.length; i++) {
String name = propertyNames[i];
// TODO: Check if EntityMode.POJO appropriate
Object value = classMetadata.getPropertyValue(bean, name, EntityMode.POJO);
if (value == null) {
continue;
}
// ignore empty Strings
if (value instanceof String) {
String string = (String) value;
if ("".equals(string)) {
continue;
}
}
// ignore any collections
if (propertyTypes[i].isCollectionType()) {
continue;
}
if (name.equals("version")) {
continue;
}
Type type = classMetadata.getPropertyType(name);
if (type.equals(Hibernate.STRING)) {
// if the property is mapped as String, find partial match
if (paramCount == 0) {
queryString.append(" where ");
} else {
queryString.append(" and ");
}
paramCount++;
queryString.append("lower(queryTarget.").append(name)
.append(") like '%" + value.toString().toLowerCase() + "%'");
} else {
// find exact match
if (paramCount == 0) {
queryString.append(" where ");
} else {
queryString.append(" and ");
}
paramCount++;
queryString.append("queryTarget.").append(name).append(" = " + value);
}
}
if (logger.isDebugEnabled()) {
logger.debug(queryString.toString());
}
// Determine number of rows
org.hibernate.Query countQuery = session.createQuery("select count(*) " + queryString.toString());
int size = ((Integer) countQuery.iterate().next()).intValue();
// Obtain requested page of query
org.hibernate.Query query = session.createQuery(queryString.toString());
query.setMaxResults(count);
query.setFirstResult(firstElement);
return new PaginatedList(query.list(), firstElement, count, size);
}
};
}
@SuppressWarnings("unchecked")
public E readId(Serializable id) {
Assert.notNull(id);
return (E) getHibernateTemplate().load(supportsClass, id);
}
@SuppressWarnings("unchecked")
public PaginatedList<E> scroll(E value, int firstElement, int maxElements, String orderByAsc) {
validateScrollMethod(value, firstElement, maxElements, orderByAsc);
return (PaginatedList) super.getHibernateTemplate()
.execute(getFindByValueCallback(value.getClass(), value, firstElement, maxElements,
Order.asc(orderByAsc)));
}
@SuppressWarnings("unchecked")
public PaginatedList<E> scrollWithSubclasses(E value, int firstElement, int maxElements, String orderByAsc) {
validateScrollMethod(value, firstElement, maxElements, orderByAsc);
return (PaginatedList) super.getHibernateTemplate()
.execute(getFindByValueCallback(this.supportsClass, value, firstElement,
maxElements, Order.asc(orderByAsc)));
}
public boolean supports(Class clazz) {
Assert.notNull(clazz);
return this.supportsClass.equals(clazz);
}
public void update(E value) {
Assert.notNull(value);
super.getHibernateTemplate().update(value);
}
private void validateScrollMethod(E value, int firstElement, int MaxElements, String orderByAsc) {
Assert.notNull(value);
Assert.hasText(orderByAsc, "An orderByAsc is required (why not use your identity property?)");
Assert.isInstanceOf(this.supportsClass, value, "Can only scroll with values this DAO supports");
}
}

View File

@ -1,124 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.hibernate;
import org.acegisecurity.domain.util.GenericsUtils;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
/**
* Java 1.5 <code>enum</code>eration compatible Hibernate 3 <code>UserType</code>.
*
* @author Ben Alex
* @version $Id$
*
* @param <E> DOCUMENT ME!
*/
public class EnumUserType<E extends Enum<E>> implements UserType {
//~ Static fields/initializers =====================================================================================
private static final int[] SQL_TYPES = {Types.VARCHAR};
//~ Instance fields ================================================================================================
private Class<E> clazz = null;
//~ Constructors ===================================================================================================
@SuppressWarnings("unchecked")
protected EnumUserType() {
this.clazz = GenericsUtils.getGeneric(getClass());
}
//~ Methods ========================================================================================================
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return cached;
}
public Object deepCopy(Object value) throws HibernateException {
return value;
}
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true;
}
if ((null == x) || (null == y)) {
return false;
}
return x.equals(y);
}
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
public boolean isMutable() {
return false;
}
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
throws HibernateException, SQLException {
String name = resultSet.getString(names[0]);
E result = null;
if (!resultSet.wasNull()) {
result = Enum.valueOf(clazz, name);
}
return result;
}
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index)
throws HibernateException, SQLException {
if (null == value) {
preparedStatement.setNull(index, Types.VARCHAR);
} else {
preparedStatement.setString(index, ((Enum) value).name());
}
}
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return original;
}
public Class returnedClass() {
return clazz;
}
public int[] sqlTypes() {
return SQL_TYPES;
}
}

View File

@ -1,143 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.hibernate;
import org.acegisecurity.domain.validation.IntrospectionManager;
import org.acegisecurity.domain.validation.ValidationRegistryManager;
import org.hibernate.EntityMode;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.type.Type;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.orm.hibernate3.HibernateSystemException;
import org.springframework.util.Assert;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* {@link IntrospectionManager} that uses Hibernate metadata to locate children.<p>Add children objects are added
* to the <code>List</code> of children objects to validate, irrespective of whether a save/update/delete operation
* will cascade to them. This is not a perfect solution, but addresses most real-world validation requirements (you
* can always implement your own <code>IntrospectionManager</code> if you prefer).</p>
* <p>This implementation only adds properties of a parent object that have a Hibernate {@link
* net.sf.hibernate.type.Type} that indicates it is an object type (ie {@link
* net.sf.hibernate.type.Type#isObjectType()}).</p>
*
* @author Matthew Porter
* @author Ben Alex
*/
public class IntrospectionManagerHibernate implements IntrospectionManager, InitializingBean {
//~ Instance fields ================================================================================================
private ValidationRegistryManager validationRegistryManager;
private SessionFactory[] sessionFactories;
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.notNull(validationRegistryManager, "ValidationRegistryManager is required");
Assert.notNull(sessionFactories, "SessionFactories are required");
Assert.notEmpty(sessionFactories, "SessionFactories are required");
// Eagerly pre-register Validators for all Hibernate metadata-defined classes
for (int i = 0; i < sessionFactories.length; i++) {
Map<String, ClassMetadata> metadataMap = this.sessionFactories[i].getAllClassMetadata();
Collection<String> mappedClasses = metadataMap.keySet();
for (Iterator<String> iter = mappedClasses.iterator(); iter.hasNext();) {
String className = iter.next();
this.validationRegistryManager.findValidator(Class.forName(className));
}
}
}
private ClassMetadata findMetadata(Class clazz) throws HibernateSystemException {
for (int i = 0; i < sessionFactories.length; i++) {
ClassMetadata result = sessionFactories[i].getClassMetadata(clazz);
if (result != null) {
return result;
}
}
return null;
}
public SessionFactory[] getSessionFactories() {
return this.sessionFactories;
}
public ValidationRegistryManager getValidationRegistryManager() {
return validationRegistryManager;
}
public void obtainImmediateChildren(Object parentObject, List<Object> allObjects) {
Assert.notNull(parentObject, "Violation of interface contract: parentObject null");
Assert.notNull(allObjects, "Violation of interface contract: allObjects null");
ClassMetadata classMetadata = null;
try {
classMetadata = findMetadata(parentObject.getClass());
if (classMetadata != null) {
String[] propertyNames = classMetadata.getPropertyNames();
for (int i = 0; i < propertyNames.length; i++) {
Type propertyType = classMetadata.getPropertyType(propertyNames[i]);
// Add this property to the List of Objects to validate
// only if a Validator is registered for that Object AND
// the object is initialized (ie not lazy loaded)
if (this.validationRegistryManager.findValidator(propertyType.getReturnedClass()) != null) {
Object childObject = classMetadata.getPropertyValue(parentObject, propertyNames[i],
EntityMode.POJO);
if ((childObject != null) && Hibernate.isInitialized(childObject)) {
if (childObject instanceof Collection) {
allObjects.addAll((Collection) childObject);
} else {
allObjects.add(childObject);
}
}
}
}
}
} catch (HibernateException he) {
throw new HibernateSystemException(he);
}
}
public void setSessionFactories(SessionFactory[] sessionFactorys) {
this.sessionFactories = sessionFactorys;
}
public void setValidationRegistryManager(ValidationRegistryManager validationRegistryManager) {
this.validationRegistryManager = validationRegistryManager;
}
}

View File

@ -1,6 +0,0 @@
<html>
<body>
<p>Hibernate-specific implementations of the domain subproject interfaces.</p>
</body>
</html>

View File

@ -1,57 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.impl;
import org.acegisecurity.domain.PersistableEntity;
/**
* An abstract implementation of {@link org.acegisecurity.domain.PersistableEntity}.
*
* @author Ben Alex
* @version $Id$
*/
public abstract class AbstractPersistableEntity extends BusinessObject implements PersistableEntity {
//~ Static fields/initializers =====================================================================================
public static final int STARTING_VERSION = 0;
//~ Instance fields ================================================================================================
private int version = STARTING_VERSION;
//~ Methods ========================================================================================================
/**
* Returns the version number, which should be managed by the persistence layer.<p>Initially all
* <code>PersistableEntity</code>s will commence with the version number defined by {@link #STARTING_VERSION}.</p>
*
* @return the version
*/
public int getVersion() {
return version;
}
/**
* Indicates whether this persistable entity has been persisted yet. Determine based on whether the {@link
* #getInternalId()} returns <code>null</code> or a non-<code>null</code> value.
*
* @return <code>true</code> if the instance has not been persisted, <code>false</code> otherwise
*/
public boolean isNew() {
return (getInternalId() == null);
}
}

View File

@ -1,73 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.impl;
import org.acegisecurity.domain.util.ReflectionToStringBuilder;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.Serializable;
/**
* A business domain object.<p>Only minimal convenience methods are provided by <code>BusinessObject</code>. Whilst
* many other methods could easily be offered (and overridden on an as-required basis) it is felt the default
* behaviour of {@link java.lang.Object} is widely understood and an appropriate default.</p>
*
* @author Carlos Sanchez
* @author Ben Alex
* @author Matthew Porter
* @version $Id$
*/
public abstract class BusinessObject implements Serializable, Cloneable {
//~ Instance fields ================================================================================================
protected final transient Log logger = LogFactory.getLog(getClass());
//~ Methods ========================================================================================================
/**
* Swallow cloning.<p>This method delegates to BeanUtils.cloneBean(). Please note that this class uses
* serialization to achieve a clone, so this may represent a performance issue in certain applications. In such
* circumstances you should override this method and provide alternative cloning logic.</p>
*
* @return a clone of the current instance
*
* @throws CloneNotSupportedException if there are any problems with swallow cloning
*
* @see java.lang.Object#clone()
* @see BeanUtils#cloneBean(Object)
*/
public Object clone() throws CloneNotSupportedException {
try {
return BeanUtils.cloneBean(this);
} catch (Exception e) {
logger.error(e);
throw new CloneNotSupportedException(e.getMessage());
}
}
/**
* Delegates to {@link CollectionIgnoringReflectionToStringBuilder}.
*
* @see java.lang.Object#toString()
*/
public String toString() {
return new ReflectionToStringBuilder(this).toString();
}
}

View File

@ -1,51 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.impl;
import java.io.Serializable;
/**
* A persistable entity that uses a <code>Integer</code> based identity.
*
* @author Ben Alex
* @version $Id$
*/
public abstract class PersistableEntityInteger extends AbstractPersistableEntity {
//~ Instance fields ================================================================================================
private Integer id;
//~ Methods ========================================================================================================
/**
* Obtains the persistence identity of this instance.
*
* @return DOCUMENT ME!
*/
public Integer getId() {
return this.id;
}
/**
* Required solely because Hibernate
*
* @return DOCUMENT ME!
*/
public Serializable getInternalId() {
return this.id;
}
}

View File

@ -1,51 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.impl;
import java.io.Serializable;
/**
* A persistable entity that uses a <code>Long</code> based identity.
*
* @author Ben Alex
* @version $Id$
*/
public abstract class PersistableEntityLong extends AbstractPersistableEntity {
//~ Instance fields ================================================================================================
private Long id;
//~ Methods ========================================================================================================
/**
* Obtains the persistence identity of this instance.
*
* @return DOCUMENT ME!
*/
public Long getId() {
return this.id;
}
/**
* Required solely because Hibernate
*
* @return DOCUMENT ME!
*/
public Serializable getInternalId() {
return this.id;
}
}

View File

@ -1,29 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.impl;
/**
* A <i>value object</i>, which means a persistable business object that does not have its own persistence
* identity.<p>Every value object belongs to a single {@link
* org.acegisecurity.domain.impl.AbstractPersistableEntity}. This is necessary so that the value object has some sort
* of persistence relationship/ownership.</p>
* <P>In addition, a value object cannot be referenced from more than one <code>PersistableEntity</code>. Use a
* <code>PersistableEntity</code> instead of a <code>PersistableValue</code> if this is a design constraint.</p>
*
* @author Ben Alex
* @version $Id$
*/
public abstract class PersistableValue extends BusinessObject {}

View File

@ -1,7 +0,0 @@
<html>
<body>
<p>Convenient domain object abstract classes, although none are mandatory/required by
other packages in this project.</p>
</body>
</html>

View File

@ -1,6 +0,0 @@
<html>
<body>
<p>Provides tools to assist develop rich domain object models.</p>
</body>
</html>

View File

@ -1,151 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.service;
import org.acegisecurity.domain.PersistableEntity;
import org.acegisecurity.domain.dao.PaginatedList;
import org.springframework.dao.DataAccessException;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* Provides fundamental services layer capabilities for a single concrete {@link
* PersistableEntity}, using JDK 1.5 generics.
*
* <P>
* A design decision was to rely on by-reference calling semantics typical of
* recommended same-JVM (colocated) deployment environments. If you are using
* remoting you may need to provide a remoting facade that returns the updated
* object to the client.
* </p>
*
* <p>
* It is not envisioned that this interface will provide <b>all</b> services layer
* functions. The significant value of a services layer is the value-add beyond
* simply fronting the DAO. The type of value-adds
* expected to be provided by a services layer include incrementing business
* identifiers (eg an invoice number); generating messages for logging/audit
* purposes (thus such messages are at a business transaction level of granularity,
* instead of DAO/persistence granularity where the overall context of the
* the message becomes unclear); updating related domain objects via
* their respective services layer beans (eg an invoice services layer bean
* would call the general journal services layer bean to create the accrual
* accounting entries); producing messages (eg notify another system the invoice
* was created or email the customer via SMTP); provide a layer to locate transaction
* and security configuration etc.
* </p>
*
* <P>
* A single <code>ImmutableManager</code> implementation will typically exist for each
* {@link org.acegisecurity.domain.PersistableEntity}, particularly given
* a <code>PersistableEntity</code> is allowed to manage multiple
* {@link org.acegisecurity.domain.impl.PersistableValue}s.
* The particular <code>PersistableEntity</code> an implementation supports
* will be expressed by the {@link #supports(Class)} method.
* </p>
*
* <p>No other part of the Domain subproject relies on this interface. If
* you would prefer to write your own services layer interfaces from scratch,
* this is not a problem at all.
*
* @author Ben Alex
* @version $Id$
*/
public interface ImmutableManager<E extends PersistableEntity> {
//~ Methods ========================================================================================================
/**
* Return all persistent instances, including subclasses.
*
* @return all persistence instances (an empty <code>List</code> will be returned if no matches are found)
*
* @throws DataAccessException DOCUMENT ME!
*/
public List<E> findAll() throws DataAccessException;
/**
* Find a <code>List</code> of <code>PersistableEntity</code>s, searched by their identifiers.
*
* @param ids collection of identifiers to locate
*
* @return the values with those identifiers (an empty <code>List</code> will be returned if no matches are found)
*
* @throws DataAccessException DOCUMENT ME!
*/
public List<E> findId(Collection<Serializable> ids)
throws DataAccessException;
/**
* Load a persistent instance by its identifier, although some properties may be lazy loaded depending on
* the underlying DAO implementation and/or persistence engine mapping document.
*
* @param id the identifier of the persistent instance desired to be retrieved
*
* @return the request item, or <code>null</code> if not found
*
* @throws DataAccessException DOCUMENT ME!
*/
public E readId(Serializable id) throws DataAccessException;
/**
* Find persistent instances with properties matching those of the passed <code>PersistableEntity</code>.<P>Persistent
* instances are matched on the basis of query by example. Properties whose value is <code>null</code>, empty
* <code>String</code>s, and any <code>Collection</code>s are ignored in the query by example evaluation.</p>
*
* @param value parameters to filter on (the class of this object will be added to the filter)
* @param firstElement the first result (start at zero to obtain all results)
* @param maxElements the maximum number of results desired for this page of the result set
*
* @return the requested page of the result list (a properly formed <code>PaginatedList</code> is returned if no
* results match)
*
* @throws DataAccessException DOCUMENT ME!
*/
public PaginatedList<E> scroll(E value, int firstElement, int maxElements)
throws DataAccessException;
/**
* Find persistent instances with properties matching those of the passed <code>PersistableEntity</code>,
* ignoring the class of the passed <code>PersistableEntity</code> (useful if you pass a superclass, as you want
* to find all subclass instances which match).
*
* @param value parameters to filter on (the class of this object will NOT be added to the filter)
* @param firstElement the first result (start at zero to obtain all results)
* @param maxElements the maximum number of results desired for this page of the result set
*
* @return the requested page of the result list (a properly formed <code>PaginatedList</code> is returned if no
* results match)
*
* @throws DataAccessException DOCUMENT ME!
*/
public PaginatedList<E> scrollWithSubclasses(E value, int firstElement, int maxElements)
throws DataAccessException;
/**
* Indicates whether the DAO instance provides persistence services for the specified class.
*
* @param clazz to test, which should be an implementation of <code>PersistableEntity</code>
*
* @return <code>true</code> or <code>false</code>, indicating whether or not the passed class is supported by this
* DAO instance
*/
public boolean supports(Class clazz);
}

View File

@ -1,82 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.service;
import org.acegisecurity.domain.PersistableEntity;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.beans.PropertyEditorSupport;
/**
* Converts between a PersistableEntity's internal ID (expressed as a String and the corresponding
* PersistableEntity sourced from an ImmutableManager).
*
* @author Ben Alex
* @version $Id$
*/
public class ImmutableManagerEditor extends PropertyEditorSupport {
//~ Instance fields ================================================================================================
private ImmutableManager immutableManager;
protected final transient Log log = LogFactory.getLog(getClass());
private final boolean fallbackToNull;
//~ Constructors ===================================================================================================
public ImmutableManagerEditor(ImmutableManager immutableManager, boolean fallbackToNull) {
Assert.notNull(immutableManager, "ImmutableManager required");
this.immutableManager = immutableManager;
this.fallbackToNull = fallbackToNull;
}
//~ Methods ========================================================================================================
public String getAsText() {
String result = null;
if (getValue() != null) {
result = ((PersistableEntity) getValue()).getInternalId().toString();
}
if (log.isDebugEnabled()) {
log.debug("Property Editor returning: " + result);
}
return result;
}
public void setAsText(String text) throws IllegalArgumentException {
if (this.fallbackToNull && !StringUtils.hasText(text)) {
// treat empty String as null value
setValue(null);
} else {
Long id = new Long(text);
PersistableEntity value = immutableManager.readId(id);
if (log.isDebugEnabled()) {
log.debug("Property Editor converted '" + text + "' to object: " + value);
}
setValue(value);
}
}
}

View File

@ -1,113 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.service;
import org.acegisecurity.domain.PersistableEntity;
import org.acegisecurity.domain.dao.Dao;
import org.acegisecurity.domain.dao.PaginatedList;
import org.acegisecurity.domain.util.GenericsUtils;
import org.springframework.context.support.ApplicationObjectSupport;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* Base {@link ImmutableManager} implementation.
*
* @author Ben Alex
* @version $Id$
*
* @param <E> DOCUMENT ME!
*/
public class ImmutableManagerImpl<E extends PersistableEntity> extends ApplicationObjectSupport
implements ImmutableManager<E> {
//~ Instance fields ================================================================================================
/** The class that this instance provides services for */
private Class supportsClass;
protected Dao<E> dao;
//~ Constructors ===================================================================================================
public ImmutableManagerImpl(Dao<E> dao) {
// work out what domain object we support
this.supportsClass = GenericsUtils.getGeneric(getClass());
Assert.notNull(this.supportsClass, "Could not determine the generics type");
Assert.isTrue(PersistableEntity.class.isAssignableFrom(supportsClass),
"supportClass is not an implementation of PersistableEntity");
// store the DAO and check it also supports our domain object type
Assert.notNull(dao,
"Non-null DAO (that supports the same domain object class as this services layer) is required as a constructor argument");
Assert.isTrue(dao.supports(supportsClass), "Dao '" + dao + "' does not support '" + supportsClass + "'");
this.dao = dao;
}
//~ Methods ========================================================================================================
public List<E> findAll() {
return dao.findAll();
}
public List<E> findId(Collection<Serializable> ids) {
Assert.notNull(ids, "Collection of IDs cannot be null");
Assert.notEmpty(ids, "There must be some values in the Collection list");
return dao.findId(ids);
}
/**
*
DOCUMENT ME!
*
* @return the sort order column to be used by default by the scroll methods
*/
protected String getDefaultSortOrder() {
return "id";
}
public E readId(Serializable id) {
Assert.notNull(id);
return dao.readId(id);
}
public PaginatedList<E> scroll(E value, int firstElement, int maxElements) {
Assert.notNull(value);
Assert.isInstanceOf(this.supportsClass, value, "Can only scroll with values this manager supports");
return dao.scroll(value, firstElement, maxElements, getDefaultSortOrder());
}
public PaginatedList<E> scrollWithSubclasses(E value, int firstElement, int maxElements) {
Assert.notNull(value);
Assert.isInstanceOf(this.supportsClass, value, "Can only scroll with values this manager supports");
return dao.scrollWithSubclasses(value, firstElement, maxElements, getDefaultSortOrder());
}
public boolean supports(Class clazz) {
Assert.notNull(clazz);
return this.supportsClass.equals(clazz);
}
}

View File

@ -1,164 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
/**
* Some utility methods to use <code>Collection</code>s.
*
* @author Carlos Sanchez
* @version $Id$
*/
public class CollectionUtils {
//~ Methods ========================================================================================================
/**
* Add an object to a <code>Set</code> and return the result.
*
* @param <E> DOCUMENT ME!
* @param set
* @param object
*
* @return
*/
public static <E> Set<E> add(Set<E> set, E object) {
set.add(object);
return set;
}
/**
* Add an object to a <code>List</code> and return the result.
*
* @param <E> DOCUMENT ME!
* @param list
* @param object
*
* @return
*/
public static <E> List<E> add(List<E> list, E object) {
list.add(object);
return list;
}
/**
* Clone a Collection copying all its elements to a new one. If map is <code>null</code> return
* <code>null</code>.
*
* @param <E> DOCUMENT ME!
* @param collection
*
* @return
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public static <E> Collection<E> clone(Collection<E> collection) {
if (collection == null) {
return null;
}
Class clazz = collection.getClass();
Collection<E> clone = null;
if (List.class.isAssignableFrom(clazz)) {
clone = new ArrayList<E>(collection);
} else if (SortedSet.class.isAssignableFrom(clazz)) {
clone = new TreeSet<E>(collection);
} else if (Set.class.isAssignableFrom(clazz)) {
clone = new HashSet<E>(collection);
} else {
throw new IllegalArgumentException("Unknown collection class: " + clazz);
}
return clone;
}
/**
* Clone a <code>Map</code> copying all its elements to a new one. If the passed argument is
* <code>null</code>, the method will return <code>null</code>.
*
* @param <K> DOCUMENT ME!
* @param <V> DOCUMENT ME!
* @param map to copy
*
* @return a copy of the <code>Map</code> passed as an argument
*
* @throws IllegalArgumentException if the <code>Map</code> implementation is not supported by this method
*/
public static <K, V> Map<K, V> clone(Map<K, V> map) {
if (map == null) {
return null;
}
Class clazz = map.getClass();
Map<K, V> clone = null;
if (SortedMap.class.isAssignableFrom(clazz)) {
clone = new TreeMap<K, V>(map);
} else if (Map.class.isAssignableFrom(clazz)) {
clone = new HashMap<K, V>(map);
} else {
throw new IllegalArgumentException("Unknown map class: " + clazz);
}
return clone;
}
public static boolean isCollection(Class theClass) {
return Collection.class.isAssignableFrom(theClass);
}
public static boolean isMap(Class theClass) {
return Map.class.isAssignableFrom(theClass);
}
/**
* Return a <code>List</code> (actually an {@link ArrayList}) with only that object.
*
* @param <E> DOCUMENT ME!
* @param object
*
* @return
*/
public static <E> List<E> newList(E object) {
return add(new ArrayList<E>(1), object);
}
/**
* Return a <code>Set</code> (actually a {@link HashSet}) with only that object.
*
* @param <E> DOCUMENT ME!
* @param object
*
* @return
*/
public static <E> Set<E> newSet(E object) {
return add(new HashSet<E>(), object);
}
}

View File

@ -1,93 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;
import java.beans.PropertyEditorSupport;
/**
* DOCUMENT ME!
*
* @author Ben Alex
* @version $Id$
*/
public class EnumEditor extends PropertyEditorSupport {
//~ Instance fields ================================================================================================
private final Class<?extends Enum> enumClass;
protected final transient Log log = LogFactory.getLog(getClass());
private final boolean fallbackToNull;
//~ Constructors ===================================================================================================
/**
* Create a new EnumEditor, which can create an Enum by retrieving
* the map of enum keys.
*
* <p>The fallbackToNull indicates whether null should be returned if
* a null String is provided to the property editor or if the provided
* String could not be used to locate an Enum. If set to true, null
* will be returned. If set to false, IllegalArgumentException will be thrown.
*/
public <E extends Enum<E>>EnumEditor(Class<E> enumClass, boolean fallbackToNull) {
this.enumClass = enumClass;
this.fallbackToNull = fallbackToNull;
}
//~ Methods ========================================================================================================
public String getAsText() {
String result = null;
if (getValue() != null) {
result = ((Enum) getValue()).name();
}
if (log.isDebugEnabled()) {
log.debug("Property Editor returning: " + result);
}
return result;
}
/**
* Parse the Enum from the given text.
*
* @param text DOCUMENT ME!
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
@SuppressWarnings("unchecked")
public void setAsText(String text) throws IllegalArgumentException {
if (this.fallbackToNull && !StringUtils.hasText(text)) {
// treat empty String as null value
setValue(null);
} else {
Enum value = Enum.valueOf(this.enumClass, text);
if (log.isDebugEnabled()) {
log.debug("Property Editor converted '" + text + "' to object: " + value);
}
setValue(value);
}
}
}

View File

@ -1,51 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.util;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* Provides a helper that locates the declarated generics type of a class.
*
* @author Ben Alex
* @version $Id$
*/
public class GenericsUtils {
//~ Methods ========================================================================================================
/**
* Locates the first generic declaration on a class.
*
* @param clazz The class to introspect
*
* @return the first generic declaration, or <code>null</code> if cannot be determined
*/
public static Class getGeneric(Class clazz) {
Type genType = clazz.getGenericSuperclass();
if (genType instanceof ParameterizedType) {
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if ((params != null) && (params.length == 1)) {
return (Class) params[0];
}
}
return null;
}
}

View File

@ -1,116 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.util;
import org.acegisecurity.domain.PersistableEntity;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Collection;
/**
* Customized Commons Lang <code>ReflectionToStringBuilder</code> that ignores collections and inaccessible (ie
* lazy-loaded) fields.
*
* @author Carlos Sanchez
* @author Ben Alex
* @version $Id$
*/
public class ReflectionToStringBuilder extends org.apache.commons.lang.builder.ReflectionToStringBuilder {
//~ Static fields/initializers =====================================================================================
private static DateFormat formatter = DateFormat.getDateTimeInstance();
//~ Instance fields ================================================================================================
protected final transient Log logger = LogFactory.getLog(getClass());
//~ Constructors ===================================================================================================
public ReflectionToStringBuilder(Object object) {
super(object, ToStringStyle.MULTI_LINE_STYLE);
}
//~ Methods ========================================================================================================
protected boolean accept(Field field) {
// Ignore if field inaccessible or collection
try {
Object o = getValue(field);
if (o != null) {
if (o instanceof PersistableEntity) {
Serializable id = ((PersistableEntity) o).getInternalId();
if (logger.isDebugEnabled()) {
logger.debug(field + " id: " + id);
}
}
if (o instanceof Collection) {
int size = ((Collection) o).size();
this.append(field.getName(), "<collection with " + size + " elements>");
if (logger.isDebugEnabled()) {
logger.debug(field + " size: " + size);
}
}
}
} catch (Exception fieldInaccessible) {
this.append(field.getName(), "<inaccessible>");
if (logger.isDebugEnabled()) {
logger.debug("Inaccessible: " + field);
}
return false;
}
if (logger.isDebugEnabled()) {
logger.debug("Accessible: " + field);
}
return true;
}
/**
* Calendar fields are formatted with DateFormat.getDateTimeInstance() instead of using
* Calendar.toString().
*
* @see org.apache.commons.lang.builder.ReflectionToStringBuilder#getValue(java.lang.reflect.Field)
*/
protected Object getValue(Field f) throws IllegalArgumentException, IllegalAccessException {
Object value = super.getValue(f);
if (Calendar.class.isInstance(value)) {
Calendar c = (Calendar) value;
return formatter.format(c.getTime());
} else {
return value;
}
}
}

View File

@ -1,6 +0,0 @@
<html>
<body>
<p>Utilities useful in the domain package.</p>
</body>
</html>

View File

@ -1,49 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.validation;
import org.springframework.validation.BindException;
/**
* Indicates a domain object wishes to perform additional binding before the
* <code>Validator</code> is called.
*
* <p>
* Typically this type of binding sets up private or protected properties that
* the end user is not responsible for modifying. Whilst generally this can be
* done by adding a hook to every property setter, the
* <code>BindBeforeValidation</code> interface provides an AOP-style approach
* that ensures missing hooks do not cause invalid object state.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface BindBeforeValidation {
//~ Methods ========================================================================================================
/**
* This method will be called by infrastructure code before attempting to validate the object. Given this
* method is called prior to validation, implementations of this method should <b>not</b> assume the object is in
* a valid state.<p>Implementations should modify the object as required so that the <code>Validator</code>
* will succeed if user-controllable properties are correct.</p>
*
* @throws BindException if there are problems that the method wish to advise (note that the <code>Validator</code>
* should be allowed to determine errors in most cases, rather than this method doing so)
*/
public void bindSupport() throws BindException;
}

View File

@ -1,49 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.validation;
import org.springframework.util.Assert;
import org.springframework.validation.BindException;
/**
* Convenience class that invokes the {@link BindBeforeValidation} interface if the passed domain object has
* requested it.
*
* @author Ben Alex
* @version $Id$
*/
public class BindBeforeValidationUtils {
//~ Methods ========================================================================================================
/**
* Call {@link BindBeforeValidation#bindSupport()} if the domain object requests it.
*
* @param domainObject to attempt to bind (never <code>null</code>)
*
* @throws BindException if the binding failed
*/
public static void bindIfRequired(Object domainObject)
throws BindException {
Assert.notNull(domainObject);
if (BindBeforeValidation.class.isAssignableFrom(domainObject.getClass())) {
BindBeforeValidation bbv = (BindBeforeValidation) domainObject;
bbv.bindSupport();
}
}
}

View File

@ -1,48 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.validation;
import java.util.List;
/**
* Indicates a concrete class capable of introspecting a domain object for its
* immediate children.
*
* <p>
* Implementations may use a choice of reflective introspection or querying a
* persistence metadata API to locate the internal children.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface IntrospectionManager {
//~ Methods ========================================================================================================
/**
* Locates any direct children of a domain object.<p>Typically used with a {@link ValidationManager} to
* validate each of the located children.</p>
* <P>Implementations should only add the <b>immediate layer of children</b>. Grandchildren,
* great-grandchildren etc should not be added.</p>
*
* @param parentObject the immediate parent which all children should share (guaranteed to never be
* <code>null</code>)
* @param allObjects the list to which this method should append each immediate child (guaranteed to never be
* <code>null</code>)
*/
public void obtainImmediateChildren(Object parentObject, List<Object> allObjects);
}

View File

@ -1,105 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.validation;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import java.lang.reflect.Method;
/**
* Advisor for the {@link ValidationInterceptor}.<p>Intended to be used with Spring's
* <code>DefaultAdvisorAutoProxyCreator</code>.</p>
* <p>Registers {@link ValidationInterceptor} for every <code>Method</code> against a class that directly or
* through its superclasses implements {@link #supportsClass} and has a signature match those defined by {@link
* #methods}.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class ValidationAdvisor extends StaticMethodMatcherPointcutAdvisor implements InitializingBean {
//~ Instance fields ================================================================================================
private Class<?extends Object> supportsClass;
private String[] methods = {"create", "update", "createOrUpdate"};
//~ Constructors ===================================================================================================
public ValidationAdvisor(ValidationInterceptor advice) {
super(advice);
if (advice == null) {
throw new AopConfigException("Cannot construct a BindAndValidateAdvisor using a "
+ "null BindAndValidateInterceptor");
}
}
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.notNull(supportsClass, "A supportsClass is required");
Assert.notNull(methods, "A list of valid methods is required");
Assert.notEmpty(methods, "A list of valid methods is required");
}
public String[] getMethods() {
return methods;
}
public Class getSupportsClass() {
return supportsClass;
}
public boolean matches(Method m, Class targetClass) {
// Check there are actual arguments
if (m.getParameterTypes().length == 0) {
return false;
}
// Check the method name matches one we're interested in
boolean found = false;
for (int i = 0; i < methods.length; i++) {
if (m.getName().equals(methods[i])) {
found = true;
}
}
if (!found) {
return false;
}
// Check the target is of the type of class we wish to advise
if (supportsClass.isAssignableFrom(targetClass)) {
return true;
}
return false;
}
public void setMethods(String[] methods) {
this.methods = methods;
}
public void setSupportsClass(Class<?extends Object> clazz) {
this.supportsClass = clazz;
}
}

View File

@ -1,99 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.validation;
import org.acegisecurity.domain.PersistableEntity;
import org.acegisecurity.domain.impl.BusinessObject;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* Calls {@link ValidationManager} for method invocations.<p>For each method invocation, any argument that is
* assignable from {@link #argumentClasses}<b>and</b> is non-<code>null</code> will be passed to the {@link
* org.acegisecurity.domain.validation.ValidationManager} for processing.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class ValidationInterceptor implements MethodInterceptor, InitializingBean {
//~ Instance fields ================================================================================================
protected final Log logger = LogFactory.getLog(getClass());
private ValidationManager validationManager;
private Class<?>[] argumentClasses = {BusinessObject.class, PersistableEntity.class};
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.notNull(validationManager, "A ValidationManager is required");
Assert.notEmpty(argumentClasses, "A list of business object classes to validate is required");
}
public Class[] getArgumentClasses() {
return argumentClasses;
}
public ValidationManager getValidationManager() {
return validationManager;
}
public Object invoke(MethodInvocation mi) throws Throwable {
Object[] args = mi.getArguments();
for (int i = 0; i < args.length; i++) {
if (shouldValidate(args[i])) {
if (logger.isDebugEnabled()) {
logger.debug("ValidationInterceptor calling for: '" + args[i] + "'");
}
validationManager.validate(args[i]);
}
}
return mi.proceed();
}
public void setArgumentClasses(Class[] argumentClasses) {
this.argumentClasses = argumentClasses;
}
public void setValidationManager(ValidationManager validationManager) {
this.validationManager = validationManager;
}
private boolean shouldValidate(Object argument) {
if (argument == null) {
return false;
}
for (int i = 0; i < argumentClasses.length; i++) {
if (argumentClasses[i].isAssignableFrom(argument.getClass())) {
return true;
}
}
return false;
}
}

View File

@ -1,42 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.validation;
import org.springframework.validation.BindException;
/**
* Able to validate any passed domain object instance, including its children.
*
* @author Ben Alex
* @version $Id$
*/
public interface ValidationManager {
//~ Methods ========================================================================================================
/**
* Validates the passed domain object, along with any children, grandchildren, great-grandchildren etc.<p>Before
* performing validation, implementations must execute {@link BindBeforeValidation} for any domain objects
* requesting it.</p>
*
* @param domainObject to validate (cannot be <code>null</code>)
*
* @throws BindException if a validation problem occurs
* @throws ValidatorNotFoundException if no matching <code>Validator</code> could be found (and the implementation
* wishes to treat this as an exception condition as opposed to logging it and continuing).
*/
public void validate(Object domainObject) throws BindException, ValidatorNotFoundException;
}

View File

@ -1,221 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.validation;
import org.acegisecurity.domain.dao.DetachmentContextHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
/**
* Default implementation of {@link ValidationManager}.
*
* @author Ben Alex
* @author Matthew E. Porter
* @version $Id$
*/
public class ValidationManagerImpl implements InitializingBean, ValidationManager {
//~ Instance fields ================================================================================================
private IntrospectionManager introspectionManager;
protected final Log logger = LogFactory.getLog(getClass());
private ValidationRegistryManager validationRegistryManager = new ValidationRegistryManagerImpl();
private boolean strictValidation = true;
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.notNull(validationRegistryManager, "A ValidationRegistryManager is required");
Assert.notNull(introspectionManager, "An IntrospectionManager is required");
}
private Validator findValidator(Class clazz) throws ValidatorNotFoundException {
Assert.notNull(clazz, "Class cannot be null");
Validator validator = this.validationRegistryManager.findValidator(clazz);
if (validator == null) {
throw new ValidatorNotFoundException("No Validator found for class '" + clazz + "'");
}
return validator;
}
public IntrospectionManager getIntrospectionManager() {
return introspectionManager;
}
public ValidationRegistryManager getValidationRegistryManager() {
return validationRegistryManager;
}
public boolean isStrictValidation() {
return strictValidation;
}
/**
* Locates all immediate children of the passed <code>parentObject</code>, adding each of those immediate
* children to the <code>allObjects</code> list and then calling this same method for each of those immediate
* children.<p>Does <b>not</b> add the passed <code>parentObject</code> to the <code>allObjects</code>
* list. The caller of this method should ensure the <code>parentObject</code> is added to the list instead.</p>
*
* @param parentObject the object we wish to locate all children for
* @param allObjects the list to add the located children to
*/
private void obtainAllChildren(Object parentObject, List<Object> allObjects) {
Assert.notNull(parentObject, "Violation of parentObject method contract");
Assert.notNull(allObjects, "Violation of allObjects method contract");
Assert.isTrue(allObjects.contains(parentObject), "List of objects missing the requested parentObject");
if (logger.isDebugEnabled()) {
logger.debug("Searching for children of " + parentObject);
}
// Add immediate children of this domain object
List<Object> currentChildren = new Vector<Object>();
introspectionManager.obtainImmediateChildren(parentObject, currentChildren);
// Now iterate the children, adding their children to the object list
Iterator<Object> childrenIter = currentChildren.iterator();
while (childrenIter.hasNext()) {
Object childObject = childrenIter.next();
if (childObject != null) {
if (allObjects.contains(childObject)) {
if (logger.isDebugEnabled()) {
logger.debug("Already processed this object (will not re-add): " + childObject);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug(
"New child object found; adding child object to list of objects, and searching for its children: "
+ childObject);
}
allObjects.add(childObject);
obtainAllChildren(childObject, allObjects);
}
}
}
}
public void setIntrospectionManager(IntrospectionManager introspectionManager) {
this.introspectionManager = introspectionManager;
}
/**
* Indicates whether a {@link ValidatorNotFoundException} should be thrown if any domain object does not
* have a corresponding <code>Validator</code>.<p>Defaults to <code>true</code>. This is a reasonable
* default, as callers of <code>ValidationManager</code> should expect the object to support validation.</p>
*
* @param strictValidation set to <code>false</code> if you wish to silently ignore any domain object that is
* missing a <code>Validator</code>
*/
public void setStrictValidation(boolean strictValidation) {
this.strictValidation = strictValidation;
}
public void setValidationRegistryManager(ValidationRegistryManager validationRegistryManager) {
this.validationRegistryManager = validationRegistryManager;
}
/**
* Validates the passed domain object, along with any children, grandchildren, great-grandchildren etc.
*
* @param domainObject to validate (cannot be <code>null</code>)
*
* @throws BindException if a validation problem occurs
* @throws ValidatorNotFoundException if no matching <code>Validator</code> could be found for the object or its
* children (only ever thrown if the {@link #strictValidation}) was set to <code>true</code>).
*/
public void validate(Object domainObject) throws BindException, ValidatorNotFoundException {
// Abort if null
Assert.notNull(domainObject, "Cannot validate a null domain object, as unable to getClass()");
// Construct a list of objects to be validated and adds self
List<Object> allObjects = new Vector<Object>();
allObjects.add(domainObject);
// Add all children (and grandchildren, great-grandchildren etc)
// of domain object to the list of objects to be validated
// (list never contains null)
obtainAllChildren(domainObject, allObjects);
Assert.notEmpty(allObjects, "The list of objects to be validated was empty");
// Process list of objects to be validated by validating each
Iterator<Object> iter = allObjects.iterator();
while (iter.hasNext()) {
Object currentDomainObject = iter.next();
Class clazz = currentDomainObject.getClass();
DetachmentContextHolder.setForceReturnOfDetachedInstances(true);
try {
// Call bindSupport() if this class wishes
BindBeforeValidationUtils.bindIfRequired(currentDomainObject);
Errors errors = new BindException(currentDomainObject, clazz.getName());
Validator v = findValidator(clazz);
// Perform validation
v.validate(currentDomainObject, errors);
// Handle validation outcome
if (errors.getErrorCount() == 0) {
if (logger.isDebugEnabled()) {
logger.debug("Validated '" + clazz + "' successfully using '" + v.getClass() + "'");
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Validated '" + clazz + "' using '" + v.getClass() + "' but errors detected");
}
throw (BindException) errors;
}
} catch (ValidatorNotFoundException validatorNotFoundException) {
if (strictValidation) {
if (logger.isErrorEnabled()) {
logger.error(validatorNotFoundException);
}
throw validatorNotFoundException;
}
if (logger.isDebugEnabled()) {
logger.debug("Could not locate validator for class '" + clazz + "'; skipping without error");
}
} finally {
DetachmentContextHolder.setForceReturnOfDetachedInstances(false);
}
}
}
}

View File

@ -1,48 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.validation;
import org.springframework.validation.Validator;
/**
* <code>ValidationRegistryManager</code> implementations are able to
* authoritatively return a <code>Validator</code> instance that is suitable
* for a given domain object.
*
* <p>
* Implementations are free to implement their own strategy for maintaining the
* list of <code>Validator</code>s, or create them on-demand if preferred.
* This interface is non-prescriptive.
* </p>
*
* @author Matthew E. Porter
* @author Ben Alex
* @version $Id$
*/
public interface ValidationRegistryManager {
//~ Methods ========================================================================================================
/**
* Obtains the <code>Validator</code> that applies for a given domain object class.
*
* @param domainClass that a <code>Validator</code> is required for
*
* @return the <code>Validator</code>, or <code>null</code> if no <code>Validator</code> is known for the indicated
* <code>domainClass</code>
*/
public Validator findValidator(Class domainClass);
}

View File

@ -1,154 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.validation;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.util.Assert;
import org.springframework.validation.Validator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* A basic implementation of {@link ValidationRegistryManager}.<p>Locates <code>Validator</code>s registered in
* bean factory.</p>
* <p>If more than one <code>Validator</code> can support a given object, the supporting <code>Validator</code>s
* will be iterated and their bean factory defined bean names will be used to attempt to select the "best matching"
* <code>Validator</code>. The lowercase version of a given object's simplified class name will be searched within the
* bean names. If more than one <code>Validator</code> contains this search criteria, an exception will be thrown as
* the actual intended <code>Validator</code> is unidentifiable.</p>
* <p>For example, say you had a PartyValidator which could validate com.foo.Party, and also its subclass,
* com.foo.Person. There is also a PersonValidator which can only validate Person. PartyValidator and PersonValidator
* are registered in the bean container as "partyValidator" and "personValidator". When
* <code>ValidationRegistryManagerImpl</code> is asked to return the <code>Validator</code> for Person, it will locate
* the two matching <code>Validator</code>s in the bean container. As there are two matching, it will look at the
* lowercase representation of the bean names and see if either contain the lower simplified class name of the object
* being search for (com.foo.Person thus becomes simply "person"). <code>ValidationRegistryManagerImpl</code> will
* then correctly return the PersonValidator for Person. If the PartyValidator had been registered with an ambiguous
* bean name of say "personAndPartyValidator", both bean names would have matched and an exception would have been
* thrown.</p>
*
* @author Matthew E. Porter
* @author Ben Alex
* @version $Id$
*/
public class ValidationRegistryManagerImpl implements ValidationRegistryManager, BeanFactoryAware {
//~ Instance fields ================================================================================================
private ListableBeanFactory bf;
private Map<Class, String> validatorMap = new HashMap<Class, String>();
//~ Methods ========================================================================================================
public Validator findValidator(Class domainClass) {
Assert.notNull(domainClass, "domainClass cannot be null");
if (validatorMap.containsKey(domainClass)) {
if (validatorMap.get(domainClass) == null) {
return null;
}
return (Validator) this.bf.getBean((String) validatorMap.get(domainClass), Validator.class);
}
// Attempt to find Validator via introspection
Map<String, Validator> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, Validator.class, true, true);
// Search all Validators for those that support the class
Set<String> candidateValidatorNames = new HashSet<String>();
Iterator<String> iter = beans.keySet().iterator();
while (iter.hasNext()) {
String beanName = iter.next();
Validator validator = beans.get(beanName);
if (validator.supports(domainClass)) {
candidateValidatorNames.add(beanName);
}
}
if (candidateValidatorNames.size() == 0) {
// No Validator found
this.validatorMap.put(domainClass, null);
return null;
} else if (candidateValidatorNames.size() == 1) {
// Only one Validator found, so return it
String validator = candidateValidatorNames.iterator().next();
this.validatorMap.put(domainClass, validator);
return beans.get(validator);
} else {
// Try to locate an entry with simple class name in it
StringBuffer sb = new StringBuffer();
Iterator<String> iterCandidates = candidateValidatorNames.iterator();
String lastFound = null;
int numberFound = 0;
while (iterCandidates.hasNext()) {
String candidate = iterCandidates.next();
sb.append(candidate);
if (iterCandidates.hasNext()) {
sb.append(",");
}
if (candidate.toLowerCase().contains(domainClass.getSimpleName().toLowerCase())) {
numberFound++;
lastFound = candidate;
}
}
if (numberFound != 1) {
throw new IllegalArgumentException("More than one Validator found (" + sb.toString()
+ ") that supports '" + domainClass
+ "', but cannot determine the most specific Validator to use; give a hint by making bean name include the simple name of the target class ('"
+ domainClass.getSimpleName().toString() + "')");
}
this.validatorMap.put(domainClass, lastFound);
return beans.get(lastFound);
}
}
public void registerValidator(Class domainClass, String beanName) {
Assert.notNull(domainClass, "domainClass cannot be null");
Assert.notNull(beanName, "beanName cannot be null");
Assert.isTrue(this.bf.containsBean(beanName), "beanName not found in context");
Assert.isInstanceOf(Validator.class, this.bf.getBean(beanName),
"beanName '" + beanName + "' must be a Validator");
Assert.isTrue(((Validator) this.bf.getBean(beanName)).supports(domainClass),
"Validator does not support " + domainClass);
this.validatorMap.put(domainClass, beanName);
}
public void setBeanFactory(BeanFactory beanFactory)
throws BeansException {
Assert.isInstanceOf(ListableBeanFactory.class, beanFactory, "BeanFactory must be ListableBeanFactory");
this.bf = (ListableBeanFactory) beanFactory;
}
}

View File

@ -1,50 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.domain.validation;
import org.acegisecurity.domain.DomainException;
/**
* Thrown if no <code>Validator</code> could be found that supports a domain object presented for validation.
*
* @author Ben Alex
* @version $Id$
*/
public class ValidatorNotFoundException extends DomainException {
//~ Constructors ===================================================================================================
/**
* Constructs a <code>ValidatorNotFoundException</code> with the specified
* message and root cause.
*
* @param msg the detail message
* @param t the root cause
*/
public ValidatorNotFoundException(String msg, Throwable t) {
super(msg, t);
}
/**
* Constructs a <code>DomainException</code> with the specified message and
* no root cause.
*
* @param msg the detail message
*/
public ValidatorNotFoundException(String msg) {
super(msg);
}
}

View File

@ -1,42 +0,0 @@
<html>
<body>
<p>Validation services for complex domain objects.</p>
<p>Generally you will write <code>Validator</code>s for each of your domain
objects, and add a {@link ValidationManager} to your application context. You
will need to wire a suitable {@link IntrospectionManager} against the
<code>ValidationManager</code> so that children of a domain object presented
for validation can be identified and in turn also validated.
<p>The {@link ValidationInterceptor} and {@link ValidationAdvisor} are provided,
although their use is not recommended against DAOs given many <code>Validator</code>s
require a DAO and this will cause a loop that results in the DAO not being
advised. Instead your DAO implementations should have their mutator methods
pass the object to the <code>ValidationManager</code> prior to persistence. This
is a non-AOP approach, but represetns a practical solution.</p>
<p>If you domain objects themselves wish to ensure they are in a valid state
prior to internal business methods being invoked, it is suggested they provide
a <code>ValidationManager</code> collaborator, and fire its validate method.
Such collaborator can be autowired during both instance retrieval and creation.
It should generally also be marked as <code>transient</code>, to avoid possible
serialisation issues if used inside a <code>HttpSession</code> or similar.</p>
<p>Sometimes domain objects need to internally update themselves before being
validated. Any such domain objects should implement {@link BindBeforeValidation}.
The <code>ValidationManager</code> will fire the related method just prior to
validation, and you can do it manually using {@link BindBeforeValidationUtils}.
Using the utility class is generally preferred over calling the method
directly, as it ignores classes that do not implement
<code>BindBeforeValidation</code>.</p>
<p>Finally, sometimes <code>Validator</code>s might need to perform queries
against a persistence or services layer. For example, the <code>Validator</code>
may be checking no other user has this username, or comparing the object's old
state to detect modifications that violate business rules. If using an ORM tool
such as Hibernate, it is recommended you use the <code>EvictionUtils</code>
static methods to remove objects from the session.
</p>
</body>
</html>

View File

@ -1 +0,0 @@
*.log

View File

@ -1,6 +0,0 @@
<html>
<body>
<p>Domain's resources.</p>
</body>
</html>

View File

@ -10,7 +10,6 @@
<module>core</module>
<module>core-tiger</module>
<module>adapters</module>
<module>domain</module>
</modules>
<description>Acegi Security System for Spring</description>

View File

@ -63,7 +63,7 @@ maven.license.licenseFile=${rootdir}/LICENSE.txt
# multiproject
maven.multiproject.basedir=${rootdir}
maven.multiproject.includes=core/project.xml,adapters/*/project.xml,samples/*/project.xml,domain/project.xml,core-tiger/project.xml
maven.multiproject.includes=core/project.xml,adapters/*/project.xml,samples/*/project.xml,core-tiger/project.xml
# excluding the attributes project since the Commons Attributes plugin causes
# problems with java 5 source code compilation