Initial commit.

This commit is contained in:
Ben Alex 2005-03-30 13:41:27 +00:00
parent 046dd2611c
commit cf241fb9ae
35 changed files with 2924 additions and 1 deletions

View File

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="samples/attributes/src/main/java"/>
<classpathentry kind="src" path="domain/src/main/java"/>
<classpathentry kind="src" path="domain/src/main/resource"/>
<classpathentry kind="src" path="domain/src/test/java"/>
<classpathentry kind="src" path="domain/src/test/resources"/>
<classpathentry kind="src" path="adapters/catalina/src/main/resources"/>
<classpathentry kind="src" path="samples/attributes/src/main/resources"/>
<classpathentry kind="src" path="samples/attributes/src/test/java"/>
@ -53,5 +57,8 @@
<classpathentry kind="var" path="MAVEN_REPO/junit/jars/junit-3.8.1.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/ehcache/jars/ehcache-1.1.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/jspapi/jars/jsp-api-2.0.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/hibernate/jars/hibernate-2.1.8.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/commons-lang/jars/commons-lang-2.0.jar"/>
<classpathentry sourcepath="DIST_BASE/commons-beanutils-1.6.1-src/src/java" kind="var" path="MAVEN_REPO/commons-beanutils/jars/commons-beanutils-1.6.1.jar"/>
<classpathentry kind="output" path="target/eclipseclasses"/>
</classpath>

39
domain/maven.xml Normal file
View File

@ -0,0 +1,39 @@
<!--
* ========================================================================
*
* 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"
>
<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>

53
domain/project.xml Normal file
View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
<extend>${basedir}/../project.xml</extend>
<pomVersion>3</pomVersion>
<artifactId>acegi-security-domain</artifactId>
<name>Acegi Security System for Spring - Domain Object Support</name>
<groupId>acegisecurity</groupId>
<siteDirectory>/home/groups/a/ac/acegisecurity/htdocs/multiproject/acegi-security-domain</siteDirectory>
<repository>
<connection>scm:cvs:pserver:anonymous@cvs.sourceforge.net:/cvsroot/acegisecurity:acegisecurity</connection>
<developerConnection>scm:cvs:ext:${maven.username}@cvs.sourceforge.net:/cvsroot/acegisecurity:acegisecurity</developerConnection>
<url>http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/acegisecurity/acegisecurity/domain/</url>
</repository>
<dependencies>
<dependency>
<groupId>hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>2.1.8</version>
<type>jar</type>
</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>acegisecurity</groupId>
<artifactId>acegi-security</artifactId>
<version>0.8.2-SNAPSHOT</version>
<type>jar</type>
</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

@ -0,0 +1,51 @@
/* 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.
*/
package net.sf.acegisecurity.domain;
import net.sf.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

@ -0,0 +1,56 @@
/* 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.
*/
package net.sf.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 net.sf.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
*/
abstract Serializable getInternalId();
}

View File

@ -0,0 +1,172 @@
/* 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.
*/
package net.sf.acegisecurity.domain.dao;
import net.sf.acegisecurity.domain.PersistableEntity;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* Provides fundamental DAO capabilities for a single concrete {@link
* PersistableEntity}.
*
* <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, casting to and from concrete {@link
* net.sf.acegisecurity.domain.PersistableEntity}s, 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 {
//~ Methods ================================================================
/**
* Create a new object, with the current {@link
* PersistableEntity#getInternalId()} value being ignored.
*
* @param value (without the identity property initialized)
*
* @return the value created (with the identity property initialised)
*/
public PersistableEntity create(PersistableEntity value);
/**
* Saves an existing object to the persistence layer, or creates a new
* object in the persistence layer. Implementations typically rely on
* {@link PersistableEntity#getInternalId()} being non-<code>null</code>
* to differentiate between persistence instances previous saved and those
* requiring initial creation.
*
* @param value to save or update
*
* @return the saved or updated (as appropriate) value
*/
public PersistableEntity createOrUpdate(PersistableEntity value);
/**
* Delete an object.
*
* @param value the value to delete
*/
public void delete(PersistableEntity value);
/**
* Return all persistent instances.
*
* @return all persistence instances (an empty <code>List</code> will be
* returned if no matches are found)
*/
public List findAll();
/**
* 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)
*/
public List findId(Collection ids);
/**
* Load a persistent instance by its identifier.
*
* @param id the identifier of the persistent instance desired to be
* retrieved
*
* @return the request item, or <code>null</code> if not found
*/
public PersistableEntity readId(Serializable id);
/**
* 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
* @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)
*/
public PaginatedList scroll(PersistableEntity value, int firstElement,
int maxElements, String orderByAsc);
/**
* 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
*
* @return the updated value
*/
public PersistableEntity update(PersistableEntity value);
}

View File

@ -0,0 +1,52 @@
/* 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.
*/
package net.sf.acegisecurity.domain.dao;
import net.sf.acegisecurity.domain.PersistableEntity;
/**
* Indicates an implementation capable of evicting {@link
* net.sf.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

@ -0,0 +1,105 @@
/* 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.
*/
package net.sf.acegisecurity.domain.dao;
import net.sf.acegisecurity.domain.PersistableEntity;
import org.springframework.util.Assert;
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 (never <code>null</code>)
*/
public static void evictIfRequired(Object daoOrServices,
PersistableEntity entity) {
Assert.notNull(entity, "Cannot evict an empty PersistableEntity object!");
EvictionCapable evictor = getEvictionCapable(daoOrServices);
if (evictor != 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 collection) {
Assert.notNull(collection, "Cannot evict a null Collection");
if (getEvictionCapable(daoOrServices) == null) {
// save expense of iterating collection
return;
}
Iterator iter = collection.iterator();
while (iter.hasNext()) {
Object obj = iter.next();
if (obj instanceof PersistableEntity) {
evictIfRequired(daoOrServices, (PersistableEntity) obj);
}
}
}
/**
* 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

@ -0,0 +1,477 @@
/* 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.
*/
package net.sf.acegisecurity.domain.dao;
import net.sf.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.Vector;
/**
* <p>
* Represents a 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$
*/
public class PaginatedList implements List {
//~ Instance fields ========================================================
protected final transient Log logger = LogFactory.getLog(getClass());
private List list;
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(PersistableEntity entity) {
if (entity == null) {
this.list = new Vector();
this.firstElement = 0;
this.maxElements = Integer.MAX_VALUE;
this.size = 0;
} else {
List list = new Vector();
list.add(entity);
this.list = list;
this.firstElement = 0;
this.maxElements = Integer.MAX_VALUE;
this.size = 1;
}
}
public PaginatedList(List list, int firstElement, int maxElements, int size) {
this.list = list;
this.firstElement = firstElement;
this.maxElements = maxElements;
this.size = size;
}
//~ Methods ================================================================
/**
* Unsupported operation
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.Collection#isEmpty()
*/
public boolean isEmpty() {
throw new UnsupportedOperationException();
}
public void setFirstElement(int firstElement) {
this.firstElement = firstElement;
}
/**
* 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();
}
public void setList(List list) {
this.list = list;
}
/**
* Get list with the elements of this page.
*
* @return this page of the results
*/
public List getList() {
return list;
}
public void setMaxElements(int maxElements) {
this.maxElements = maxElements;
}
/**
* 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();
}
/**
* Set the number of elements in all the pages
*
* @param size DOCUMENT ME!
*/
public void setSize(int size) {
this.size = size;
}
/**
* 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, Object 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(Object 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 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 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 Object get(int arg0) {
return list.get(arg0);
}
/**
* 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();
}
public Iterator iterator() {
return new PaginatedListIterator(this);
}
/**
* 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 listIterator() {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.List#listIterator(int)
*/
public ListIterator listIterator(int arg0) {
throw new UnsupportedOperationException();
}
/**
* Unsupported operation
*
* @param arg0 DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws UnsupportedOperationException
*
* @see java.util.List#remove(int)
*/
public Object 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 Object set(int arg0, Object arg1) {
throw new UnsupportedOperationException();
}
/**
* 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 subList(int arg0, int arg1) {
throw new UnsupportedOperationException();
}
public Object[] toArray() {
return list.toArray();
}
public Object[] toArray(Object[] arg0) {
if (logger.isDebugEnabled()) {
logger.debug("List size when convert to array "
+ list.toArray().length);
}
return list.toArray(arg0);
}
}

View File

@ -0,0 +1,92 @@
/* 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.
*/
package net.sf.acegisecurity.domain.dao;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* An iterator of the <code>PaginatedList</code>.
*
* @author Carlos Sanchez
* @version $Id$
*/
public class PaginatedListIterator implements Iterator {
//~ Instance fields ========================================================
private Iterator iterator;
private PaginatedList list;
private int i = 0;
//~ Constructors ===========================================================
/**
* DOCUMENT ME!
*
* @param list
*/
public PaginatedListIterator(PaginatedList list) {
this.list = list;
}
//~ Methods ================================================================
/**
* @see java.util.Iterator#hasNext()
*/
public boolean hasNext() {
return i < list.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 Object next() {
if (i == list.getFirstElement()) {
iterator = list.getList().iterator();
}
if ((i >= list.getFirstElement())
&& (i < (list.getFirstElement() + list.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

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

View File

@ -0,0 +1,269 @@
/* 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.
*/
package net.sf.acegisecurity.domain.hibernate;
import net.sf.acegisecurity.domain.PersistableEntity;
import net.sf.acegisecurity.domain.dao.Dao;
import net.sf.acegisecurity.domain.dao.EvictionCapable;
import net.sf.acegisecurity.domain.dao.PaginatedList;
import net.sf.hibernate.Criteria;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.expression.Expression;
import net.sf.hibernate.expression.MatchMode;
import net.sf.hibernate.expression.Order;
import net.sf.hibernate.metadata.ClassMetadata;
import net.sf.hibernate.type.Type;
import org.springframework.orm.hibernate.HibernateCallback;
import org.springframework.orm.hibernate.HibernateObjectRetrievalFailureException;
import org.springframework.orm.hibernate.support.HibernateDaoSupport;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* {@link Dao} implementation that uses Hibernate for persistence.
*
* @author Ben Alex
* @version $Id$
*/
public class DaoHibernate extends HibernateDaoSupport implements Dao,
EvictionCapable {
//~ Instance fields ========================================================
/** The class that this instance provides services for */
private Class supportsClass;
//~ Methods ================================================================
public void setSupportsClass(Class supportClass) {
this.supportsClass = supportClass;
}
public Class getSupportsClass() {
return supportsClass;
}
public PersistableEntity create(PersistableEntity value) {
Assert.notNull(value);
getHibernateTemplate().save(value);
return readId(value.getInternalId());
}
public PersistableEntity createOrUpdate(PersistableEntity value) {
Assert.notNull(value);
if (value.getInternalId() == null) {
return create(value);
} else {
return update(value);
}
}
public void delete(PersistableEntity value) {
Assert.notNull(value);
getHibernateTemplate().delete(value);
}
public void evict(PersistableEntity entity) {
Assert.notNull(entity);
getHibernateTemplate().evict(entity);
}
public List findAll() {
return getHibernateTemplate().loadAll(supportsClass);
}
public List findId(Collection ids) {
Assert.notNull(ids, "Collection of IDs cannot be null");
Assert.notEmpty(ids, "There must be some values in the Collection list");
return (List) getHibernateTemplate().execute(getFindByIdCallback(ids));
}
public PersistableEntity readId(Serializable id) {
Assert.notNull(id);
try {
return (PersistableEntity) getHibernateTemplate().load(supportsClass,
id);
} catch (HibernateObjectRetrievalFailureException notFound) {
return null;
}
}
public PaginatedList scroll(PersistableEntity value, int firstElement,
int maxElements, String orderByAsc) {
Assert.notNull(value);
Assert.hasText(orderByAsc,
"An orderByAsc is required (why not use your identity property?)");
return (PaginatedList) getHibernateTemplate().execute(getFindByValueCallback(
value, firstElement, maxElements, Order.asc(orderByAsc)));
}
public boolean supports(Class clazz) {
Assert.notNull(clazz);
return this.supportsClass.equals(clazz);
}
public PersistableEntity update(PersistableEntity value) {
Assert.notNull(value);
getHibernateTemplate().update(value);
return readId(value.getInternalId());
}
/**
* Custom initialization behavior. Called by superclass.
*
* @throws Exception if initialization fails
*/
protected final void initDao() throws Exception {
Assert.notNull(supportsClass, "supportClass is required");
Assert.isTrue(PersistableEntity.class.isAssignableFrom(supportsClass),
"supportClass is not an implementation of PersistableEntity");
initHibernateDao();
}
/**
* Allows subclasses to provide custom initialization behaviour. Called
* during {@link #initDao()}.
*
* @throws Exception
*/
protected void initHibernateDao() throws Exception {}
/**
* 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 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 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 Object bean,
final int firstElement, final int count, final Order order) {
return new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException {
Criteria criteria = session.createCriteria(bean.getClass());
criteria.addOrder(order);
ClassMetadata classMetadata = getSessionFactory()
.getClassMetadata(bean
.getClass());
/* 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];
Object value = classMetadata.getPropertyValue(bean, name);
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].isPersistentCollectionType()) {
continue;
}
Type type = classMetadata.getPropertyType(name);
if (name.equals("version")) {
continue;
}
if (type.equals(Hibernate.STRING)) {
// if the property is mapped as String, find partial match
criteria.add(Expression.ilike(name,
value.toString(), MatchMode.ANYWHERE));
} else {
// find exact match
criteria.add(Expression.eq(name, value));
}
}
/*
* TODO Use Criteria.count() when available in next Hibernate
* versions
*/
int size = criteria.list().size();
List list = criteria.setFirstResult(firstElement)
.setMaxResults(count).list();
return new PaginatedList(list, firstElement, count, size);
}
};
}
}

View File

@ -0,0 +1,103 @@
/* 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.
*/
package net.sf.acegisecurity.domain.hibernate;
import net.sf.acegisecurity.domain.validation.IntrospectionManager;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.metadata.ClassMetadata;
import net.sf.hibernate.type.Type;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.orm.hibernate.HibernateSystemException;
import org.springframework.util.Assert;
import java.util.List;
/**
* {@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 SessionFactory sessionFactory;
//~ Methods ================================================================
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(sessionFactory, "SessionFactory is required");
}
public void obtainImmediateChildren(Object parentObject, List allObjects) {
Assert.notNull(parentObject,
"Violation of interface contract: parentObject null");
Assert.notNull(allObjects,
"Violation of interface contract: allObjects null");
ClassMetadata classMetadata = null;
try {
classMetadata = sessionFactory.getClassMetadata(parentObject
.getClass());
if (classMetadata != null) {
String[] propertyNames = classMetadata.getPropertyNames();
for (int i = 0; i < propertyNames.length; i++) {
Type propertyType = classMetadata.getPropertyType(propertyNames[i]);
if (propertyType.isObjectType()) {
allObjects.add(classMetadata.getPropertyValue(
parentObject, propertyNames[i]));
}
}
}
} catch (HibernateException he) {
throw new HibernateSystemException(he);
}
}
}

View File

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

View File

@ -0,0 +1,77 @@
/* 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.
*/
package net.sf.acegisecurity.domain.impl;
import net.sf.acegisecurity.domain.PersistableEntity;
/**
* An abstract implementation of {@link
* net.sf.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 ================================================================
/**
* 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 final boolean isNew() {
return (getInternalId() == null);
}
/**
* 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 final int getVersion() {
return version;
}
/**
* Sets the version numbers. Should only be used by the persistence layer.
*
* @param version the new version number to use
*
* @hibernate.version type="integer"
*/
protected final void setVersion(int version) {
this.version = version;
}
}

View File

@ -0,0 +1,81 @@
/* 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.
*/
package net.sf.acegisecurity.domain.impl;
import net.sf.acegisecurity.domain.util.CollectionIgnoringReflectionToStringBuilder;
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
* @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().
* </p>
*
* @return a clone of the current instance
*
* @throws IllegalStateException if there are any problems with swallow
* cloning
*
* @see java.lang.Object#clone()
* @see BeanUtils#cloneBean(Object)
*/
public Object clone() {
try {
return BeanUtils.cloneBean(this);
} catch (Exception e) {
logger.error(e);
throw new IllegalStateException(e);
}
}
/**
* Delegates to {@link CollectionIgnoringReflectionToStringBuilder}.
*
* @see java.lang.Object#toString()
*/
public String toString() {
return new CollectionIgnoringReflectionToStringBuilder(this).toString();
}
}

View File

@ -0,0 +1,78 @@
/* 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.
*/
package net.sf.acegisecurity.domain.impl;
import java.io.Serializable;
/**
* A persistable entity that uses an <code>Integer</code> based identity.
*
* @author Ben Alex
* @version $Id$
*/
public abstract class PersistableEntityInteger extends AbstractPersistableEntity {
//~ Instance fields ========================================================
private Integer id;
//~ Methods ================================================================
/**
* DO NOT USE DIRECTLY.
*
* <p>
* Typically only used by the persistence layer, but provided with public
* visibility to not limit flexibility.
* </p>
*
* @param id the new instance identity
*/
public void setId(Integer id) {
this.id = id;
}
/**
* Obtains the persistence identity of this instance.
*
* @return the instance's identity
*
* @hibernate.id generator-class="sequence"
*/
public Integer getId() {
return id;
}
/**
* DO NOT USE DIRECTLY.
*
* <p>
* Use {@link #getId()} instead, as it provides the correct return type.
* This method is only provided for use by the persistence layer and to
* satisfy the {@link net.sf.acegisecurity.domain.PersistableEntity}
* interface contract.
* </p>
*
* <p>
* Internally delegates to {@link #getId()}.
* </p>
*
* @return the instance's identity
*/
public Serializable getInternalId() {
return this.getId();
}
}

View File

@ -0,0 +1,78 @@
/* 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.
*/
package net.sf.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 ================================================================
/**
* DO NOT USE DIRECTLY.
*
* <p>
* Typically only used by the persistence layer, but provided with public
* visibility to not limit flexibility.
* </p>
*
* @param id the new instance identity
*/
public void setId(Long id) {
this.id = id;
}
/**
* Obtains the persistence identity of this instance.
*
* @return the instance's identity
*
* @hibernate.id generator-class="sequence"
*/
public Long getId() {
return id;
}
/**
* DO NOT USE DIRECTLY.
*
* <p>
* Use {@link #getId()} instead, as it provides the correct return type.
* This method is only provided for use by the persistence layer and to
* satisfy the {@link net.sf.acegisecurity.domain.PersistableEntity}
* interface contract.
* </p>
*
* <p>
* Internally delegates to {@link #getId()}.
* </p>
*
* @return the instance's identity
*/
public Serializable getInternalId() {
return this.getId();
}
}

View File

@ -0,0 +1,38 @@
/* 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.
*/
package net.sf.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
* net.sf.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

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

View File

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

View File

@ -0,0 +1,51 @@
/* 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.
*/
package net.sf.acegisecurity.domain.util;
import java.lang.reflect.Field;
/**
* A <code>toString()</code> builder that ignores collections.
*
* @author Carlos Sanchez
* @version $Id$
*
* @see org.apache.commons.lang.builder.ReflectionToStringBuilder
*/
public class CollectionIgnoringReflectionToStringBuilder
extends ReflectionToStringBuilder {
//~ Constructors ===========================================================
public CollectionIgnoringReflectionToStringBuilder(Object object) {
super(object);
}
//~ Methods ================================================================
/**
* Check if the field is a collection and return false in that case.
*
* @see org.apache.commons.lang.builder.ReflectionToStringBuilder#accept(java.lang.reflect.Field)
*/
protected boolean accept(Field field) {
if (CollectionUtils.isCollection(field.getType())) {
return false;
}
return super.accept(field);
}
}

View File

@ -0,0 +1,162 @@
/* 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.
*/
package net.sf.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 ================================================================
public static boolean isCollection(Class theClass) {
return Collection.class.isAssignableFrom(theClass);
}
public static boolean isMap(Class theClass) {
return Map.class.isAssignableFrom(theClass);
}
/**
* Add an object to a <code>Set</code> and return the result.
*
* @param set
* @param object
*
* @return
*/
public static Set add(Set set, Object object) {
set.add(object);
return set;
}
/**
* Add an object to a <code>List</code> and return the result.
*
* @param list
* @param object
*
* @return
*/
public static List add(List list, Object 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 collection
*
* @return
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public static Collection clone(Collection collection) {
if (collection == null) {
return null;
}
Class clazz = collection.getClass();
Collection clone = null;
if (List.class.isAssignableFrom(clazz)) {
clone = new ArrayList(collection);
} else if (SortedSet.class.isAssignableFrom(clazz)) {
clone = new TreeSet(collection);
} else if (Set.class.isAssignableFrom(clazz)) {
clone = new HashSet(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 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 Map clone(Map map) {
if (map == null) {
return null;
}
Class clazz = map.getClass();
Map clone = null;
if (SortedMap.class.isAssignableFrom(clazz)) {
clone = new TreeMap(map);
} else if (Map.class.isAssignableFrom(clazz)) {
clone = new HashMap(map);
} else {
throw new IllegalArgumentException("Unknown map class: " + clazz);
}
return clone;
}
/**
* Return a <code>List</code> (actually an {@link ArrayList}) with only
* that object.
*
* @param object
*
* @return
*/
public static List newList(Object object) {
return add(new ArrayList(1), object);
}
/**
* Return a <code>Set</code> (actually a {@link HashSet}) with only that
* object.
*
* @param object
*
* @return
*/
public static Set newSet(Object object) {
return add(new HashSet(), object);
}
}

View File

@ -0,0 +1,67 @@
/* 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.
*/
package net.sf.acegisecurity.domain.util;
import org.apache.commons.lang.builder.ToStringStyle;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.util.Calendar;
/**
* Customized Commons Lang <code>ReflectionToStringBuilder</code>.
*
* @author Carlos Sanchez
* @version $Revision$
*
* @see org.apache.commons.lang.builder.ReflectionToStringBuilder
*/
public class ReflectionToStringBuilder
extends org.apache.commons.lang.builder.ReflectionToStringBuilder {
//~ Static fields/initializers =============================================
private static DateFormat formatter = DateFormat.getDateTimeInstance();
//~ Constructors ===========================================================
public ReflectionToStringBuilder(Object object) {
super(object, ToStringStyle.MULTI_LINE_STYLE);
}
//~ Methods ================================================================
/**
* 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

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

View File

@ -0,0 +1,57 @@
/* 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.
*/
package net.sf.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

@ -0,0 +1,50 @@
/* 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.
*/
package net.sf.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

@ -0,0 +1,55 @@
/* 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.
*/
package net.sf.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 allObjects);
}

View File

@ -0,0 +1,115 @@
/* 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.
*/
package net.sf.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 supportsClass;
private String[] methods = {"create", "update"};
//~ Constructors ===========================================================
public ValidationAdvisor(ValidationInterceptor advice) {
super(advice);
if (advice == null) {
throw new AopConfigException(
"Cannot construct a BindAndValidateAdvisor using a "
+ "null BindAndValidateInterceptor");
}
}
//~ Methods ================================================================
public void setMethods(String[] methods) {
this.methods = methods;
}
public String[] getMethods() {
return methods;
}
public void setSupportsClass(Class clazz) {
this.supportsClass = clazz;
}
public Class getSupportsClass() {
return supportsClass;
}
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 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;
}
}

View File

@ -0,0 +1,107 @@
/* 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.
*/
package net.sf.acegisecurity.domain.validation;
import net.sf.acegisecurity.domain.PersistableEntity;
import net.sf.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 net.sf.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 setArgumentClasses(Class[] argumentClasses) {
this.argumentClasses = argumentClasses;
}
public Class[] getArgumentClasses() {
return argumentClasses;
}
public void setValidationManager(ValidationManager validationManager) {
this.validationManager = validationManager;
}
public ValidationManager getValidationManager() {
return validationManager;
}
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 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();
}
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

@ -0,0 +1,49 @@
/* 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.
*/
package net.sf.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

@ -0,0 +1,254 @@
/* 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.
*/
package net.sf.acegisecurity.domain.validation;
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
* @version $Id$
*/
public class ValidationManagerImpl implements InitializingBean,
ValidationManager {
//~ Instance fields ========================================================
protected final Log logger = LogFactory.getLog(getClass());
private IntrospectionManager introspectionManager;
private List validators;
private boolean strictValidation = true;
//~ Methods ================================================================
public void setIntrospectionManager(
IntrospectionManager introspectionManager) {
this.introspectionManager = introspectionManager;
}
public IntrospectionManager getIntrospectionManager() {
return introspectionManager;
}
/**
* Indicates whether a {@link ValidatorNotFoundException} should be thrown
* if any domain object does not have a corresponding
* <code>Validator</code> defined against the {@link #validators}.
*
* <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 boolean isStrictValidation() {
return strictValidation;
}
/**
* Sets the {@link Validator} objects to be used.
*
* @param newList that should be used for validation.
*/
public void setValidators(List newList) {
Assert.notNull(newList, "A list of Validators is required");
Assert.isTrue(newList.size() > 0,
"At least one Validator must be defined");
Iterator iter = newList.iterator();
while (iter.hasNext()) {
Object currentObject = null;
currentObject = iter.next();
Assert.isInstanceOf(Validator.class, currentObject,
"Validator '" + currentObject
+ "' must be an instance of Validator");
}
this.validators = newList;
}
public List getValidators() {
return this.validators;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(validators, "A list of Validators is required");
Assert.isTrue(validators.size() > 0,
"At least one Validator must be defined");
Assert.notNull(introspectionManager,
"An IntrospectionManager is required");
}
/**
* 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 add self
List allObjects = new Vector();
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 iter = allObjects.iterator();
while (iter.hasNext()) {
Object currentDomainObject = iter.next();
Class clazz = currentDomainObject.getClass();
try {
Errors errors = new BindException(currentDomainObject,
clazz.getName());
Validator v = findValidator(clazz);
// Call bindSupport() if this class wishes
BindBeforeValidationUtils.bindIfRequired(currentDomainObject);
// Perform validation
v.validate(currentDomainObject, errors);
// Handle validation outcome
if (errors.getErrorCount() == 0) {
if (logger.isDebugEnabled()) {
logger.debug("Validated '" + clazz + "' successfully");
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Validated '" + clazz
+ "' 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");
}
}
}
}
private Validator findValidator(Class clazz)
throws ValidatorNotFoundException {
Assert.notNull(clazz, "Class cannot be null");
Iterator iter = validators.iterator();
while (iter.hasNext()) {
Validator validator = (Validator) iter.next();
if (validator.supports(clazz)) {
return validator;
}
}
throw new ValidatorNotFoundException("No Validator found for class '"
+ clazz + "'");
}
/**
* 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 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");
// Add immediate children of this domain object
List currentChildren = new Vector();
introspectionManager.obtainImmediateChildren(parentObject,
currentChildren);
// Add the children
allObjects.addAll(currentChildren);
// Now iterate the children, adding their children to the object list
Iterator childrenIter = currentChildren.iterator();
while (childrenIter.hasNext()) {
Object childObject = childrenIter.next();
if (childObject != null) {
obtainAllChildren(childObject, allObjects);
}
}
}
}

View File

@ -0,0 +1,51 @@
/* 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.
*/
package net.sf.acegisecurity.domain.validation;
import net.sf.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

@ -0,0 +1,46 @@
<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} should be
used against each of your data access object (DAO) mutator methods, such as
<code>SomeDao.create(Object)</code> and <code>SomeDao.update(Object)</code>.
The interceptor will cause the <code>Object</code> to be presented to the
<code>ValidationManager</code>, thus ensuring the domain object instance is in
a valid state before being persisted.</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. If using an ORM tool such as
Hibernate, it is recommended your <code>Validator</code>s subclass a common
abstract parent that provides an <code>evict(Object)</code> and
<code>evict(Collection)</code> method. That way your <code>Validator</code>s
can utilise standard services layer or DAO methods as required to retrieve
other domain objects, and flush them from the session cache afterwards. Whilst
this is more a <code>Validator</code> design choice than something mandated by
this package, we have found it a worthwhile pattern in real-world applications.
</p>
</body>
</html>

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
maven.multiproject.includes=core/project.xml,adapters/*/project.xml,samples/*/project.xml,domain/project.xml
# multichanges
maven.multichanges.basedir=${maven.multiproject.basedir}