diff --git a/domain/src/main/java/org/acegisecurity/domain/PersistableEntity.java b/domain/src/main/java/org/acegisecurity/domain/PersistableEntity.java index 9726bbfcf6..65ec93ca50 100644 --- a/domain/src/main/java/org/acegisecurity/domain/PersistableEntity.java +++ b/domain/src/main/java/org/acegisecurity/domain/PersistableEntity.java @@ -52,5 +52,5 @@ public interface PersistableEntity { * * @return the persistence identity of this instance */ - abstract Serializable getInternalId(); + public abstract Serializable getInternalId(); } diff --git a/domain/src/main/java/org/acegisecurity/domain/dao/Dao.java b/domain/src/main/java/org/acegisecurity/domain/dao/Dao.java index 42b69fa80c..58a8a27fe2 100644 --- a/domain/src/main/java/org/acegisecurity/domain/dao/Dao.java +++ b/domain/src/main/java/org/acegisecurity/domain/dao/Dao.java @@ -15,13 +15,13 @@ package org.acegisecurity.domain.dao; -import org.acegisecurity.domain.PersistableEntity; - import java.io.Serializable; - import java.util.Collection; import java.util.List; +import org.acegisecurity.domain.PersistableEntity; +import org.springframework.dao.DataAccessException; + /** * Provides fundamental DAO capabilities for a single concrete {@link * PersistableEntity}, using JDK 1.5 generics. @@ -44,9 +44,7 @@ import java.util.List; * 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 - * org.acegisecurity.domain.PersistableEntity}s, workflow and business - * logic should take place. + * authorization, workflow and business logic should take place. *

* *

@@ -67,17 +65,15 @@ public interface Dao { * PersistableEntity#getInternalId()} value being ignored. * * @param value (without the identity property initialized) - * - * @return the value created (with the identity property initialised) */ - public E create(E value); + public void create(E value) throws DataAccessException; /** * Delete an object. * * @param value the value to delete */ - public void delete(E value); + public void delete(E value) throws DataAccessException; /** * Return all persistent instances, including subclasses. @@ -85,7 +81,7 @@ public interface Dao { * @return all persistence instances (an empty List will be * returned if no matches are found) */ - public List findAll(); + public List findAll() throws DataAccessException; /** * Find a List of PersistableEntitys, searched by @@ -96,7 +92,7 @@ public interface Dao { * @return the values with those identifiers (an empty List * will be returned if no matches are found) */ - public List findId(Collection ids); + public List findId(Collection ids) throws DataAccessException; /** * Load a persistent instance by its identifier, although some properties @@ -108,19 +104,8 @@ public interface Dao { * * @return the request item, or null if not found */ - public E readId(Serializable id); + public E readId(Serializable id) throws DataAccessException; - /** - * Loads a persistent instance by its identifier, along with any - * lazy loaded properties associated with that instance. - * - * @param id the identifier of the persistent instance desired to be - * retrieved - * - * @return the request item, or null if not found - */ - public E readPopulatedId(Serializable id); - /** * Find persistent instances with properties matching those of the passed * PersistableEntity. @@ -146,36 +131,7 @@ public interface Dao { * PaginatedList is returned if no results match) */ public PaginatedList scroll(E value, int firstElement, - int maxElements, String orderByAsc); - - /** - * Find persistent instances with properties matching those of the passed - * PersistableEntity, with a guarantee the returned results - * will have each of the value class' immediate properties - * initialized. - * - *

- * Persistent instances are matched on the basis of query by example. - * Properties whose value is null, empty - * Strings, and any Collections are ignored in - * the query by example evaluation. - *

- * - * @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 - * PersistableEntity that should be used to order the - * results - * - * @return the requested page of the result list (a properly formed - * PaginatedList is returned if no results match) - */ - public PaginatedList scrollPopulated(E value, int firstElement, - int maxElements, String orderByAsc); + int maxElements, String orderByAsc) throws DataAccessException; /** * Find persistent instances with properties matching those of the passed @@ -197,31 +153,7 @@ public interface Dao { * PaginatedList is returned if no results match) */ public PaginatedList scrollWithSubclasses(E value, int firstElement, - int maxElements, String orderByAsc); - - /** - * Find persistent instances with properties matching those of the passed - * PersistableEntity, ignoring the class of the passed - * PersistableEntity (useful if you pass a superclass, as you - * want to find all subclass instances which match). Guarantees the returned - * results will have each of the DAO's supports class' immediate - * properties initialized. - * - * @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 - * PersistableEntity that should be used to order the - * results - * - * @return the requested page of the result list (a properly formed - * PaginatedList is returned if no results match) - */ - public PaginatedList scrollPopulatedWithSubclasses(E value, int firstElement, - int maxElements, String orderByAsc); + int maxElements, String orderByAsc) throws DataAccessException; /** * Indicates whether the DAO instance provides persistence services for the @@ -240,8 +172,6 @@ public interface Dao { * * @param value to update, with the PersistableEntity having a * non-null identifier - * - * @return the updated value */ - public E update(E value); + public void update(E value) throws DataAccessException; } diff --git a/domain/src/main/java/org/acegisecurity/domain/hibernate/DaoHibernate.java b/domain/src/main/java/org/acegisecurity/domain/hibernate/DaoHibernate.java index 8099ffdbc6..a98e785510 100644 --- a/domain/src/main/java/org/acegisecurity/domain/hibernate/DaoHibernate.java +++ b/domain/src/main/java/org/acegisecurity/domain/hibernate/DaoHibernate.java @@ -16,36 +16,26 @@ package org.acegisecurity.domain.hibernate; import java.io.Serializable; -import java.lang.reflect.Method; import java.util.Collection; import java.util.List; import org.acegisecurity.domain.PersistableEntity; import org.acegisecurity.domain.dao.Dao; -import org.acegisecurity.domain.dao.DetachmentContextHolder; -import org.acegisecurity.domain.dao.EvictionCapable; -import org.acegisecurity.domain.dao.InitializationCapable; import org.acegisecurity.domain.dao.PaginatedList; import org.acegisecurity.domain.util.GenericsUtils; -import org.acegisecurity.domain.validation.ValidationManager; - import org.hibernate.Criteria; import org.hibernate.EntityMode; -import org.hibernate.FetchMode; 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.MatchMode; import org.hibernate.criterion.Order; import org.hibernate.metadata.ClassMetadata; import org.hibernate.type.Type; -import org.springframework.dao.DataIntegrityViolationException; import org.springframework.orm.hibernate3.HibernateCallback; -import org.springframework.orm.hibernate3.HibernateTemplate; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.util.Assert; -import org.springframework.validation.BindException; /** @@ -55,180 +45,65 @@ import org.springframework.validation.BindException; * @author Matthew Porter * @version $Id$ */ -public class DaoHibernate extends HibernateDaoSupport implements Dao, - EvictionCapable, InitializationCapable { +public class DaoHibernate extends HibernateDaoSupport implements Dao { //~ Instance fields ======================================================== /** The class that this instance provides services for */ private Class supportsClass; - - /** Enables mutator methods to validate an object prior to persistence */ - private ValidationManager validationManager; - public DaoHibernate() { + 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()); - if (this.supportsClass == null) { - if (logger.isWarnEnabled()) { - logger.warn("Could not determine the generics type - you will need to set manually"); - } - } + Assert.notNull(this.supportsClass, "Could not determine the generics type"); } //~ Methods ================================================================ - /** - * Obtains a HibernateTemplate that uses the appropriate Session - * based on the value of {@link DetachmentContextHolder}. - * - *

Specifically, if DetachmentContextHolder requires detached instances, - * the method will build a new Session (ignore the current thread-bound - * Session) and use that new Session in the HibernateTemplate. - * If DetachmentContextHolder is at its fault false value, the - * returned HibernateTemplate will simply use the Session obtained - * from the superclass, which is generally the same Session as used for the - * transaction. - * - * @return the template, containing the correct Session based on the - * DetachmentContactHolder request - */ - protected HibernateTemplate doGetHibernateTemplate() { - if (DetachmentContextHolder.isForceReturnOfDetachedInstances()) { - HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory()); - hibernateTemplate.setAlwaysUseNewSession(true); - return hibernateTemplate; - } else { - return super.getHibernateTemplate(); - } - } - - public void setSupportsClass(Class supportClass) { - this.supportsClass = supportClass; - } - - public Class getSupportsClass() { - return supportsClass; - } - - public ValidationManager getValidationManager() { - return validationManager; - } - - public void setValidationManager(ValidationManager validationManager) { - this.validationManager = validationManager; - } - - public E create(E value) { + public void create(E value) { Assert.notNull(value); - validate(value); - doGetHibernateTemplate().save(value); - - return readId(value.getInternalId()); + super.getHibernateTemplate().save(value); } - - protected void validate(E value) throws DataIntegrityViolationException { - try { - validationManager.validate(value); - } catch (BindException bindException) { - throw new DataIntegrityViolationException("Entity state is invalid", bindException); - } - } public void delete(E value) { Assert.notNull(value); - validate(value); - doGetHibernateTemplate().delete(value); + super.getHibernateTemplate().delete(value); } - public void evict(PersistableEntity entity) { - Assert.notNull(entity); - doGetHibernateTemplate().evict(entity); + @SuppressWarnings("unchecked") + public List findAll() { + return super.getHibernateTemplate().loadAll(supportsClass); } - public List findAll() { - return doGetHibernateTemplate().loadAll(supportsClass); - } - - public List findId(Collection ids) { + @SuppressWarnings("unchecked") + 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) doGetHibernateTemplate().execute(getFindByIdCallback(ids)); + return (List) super.getHibernateTemplate().execute(getFindByIdCallback(ids)); } - private E readId(final Serializable id, final boolean populate) { + @SuppressWarnings("unchecked") + public E readId(Serializable id) { Assert.notNull(id); - return (E) doGetHibernateTemplate().execute(new HibernateCallback() { - public Object doInHibernate(Session session) throws HibernateException { - E obj = (E) session.get(supportsClass, id); - if (populate) { - initializeAllZeroArgumentGetters(obj); - } - return obj; - } - }, true); + return (E) getHibernateTemplate().load(supportsClass, id); } - public E readId(Serializable id) { - Assert.notNull(id); - return readId(id, false); - } - - public E readPopulatedId(Serializable id) { - Assert.notNull(id); - return readId(id, true); - } - - /** - * Locates every get*() method against the passed entity - * and calls it. This method does not nest its initialization beyond - * the immediately passed entity. - * - *

For example, a Foo object might provide a getBar() method. - * Passing the Foo instance to this method will guarantee getBar() is - * available to the services layer. However, if getBar() returned a Bar - * which in turn provided a getCar() method, there is NO GUARANTEE - * the getCar() method will be initialized. - * - * @param entity for which its immediate getters should be initialized - */ - protected void initializeAllZeroArgumentGetters(E 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 { - Hibernate.initialize(methods[i].invoke(entity, new Object[] {})); - } catch (Exception ignored) {} - } - } - } - - public PaginatedList scroll(E value, int firstElement, + @SuppressWarnings("unchecked") + public PaginatedList scroll(E value, int firstElement, int maxElements, String orderByAsc) { validateScrollMethod(value, firstElement, maxElements, orderByAsc); - return (PaginatedList) doGetHibernateTemplate().execute(getFindByValueCallback( - value.getClass(), false, value, firstElement, maxElements, Order.asc(orderByAsc))); + return (PaginatedList) super.getHibernateTemplate().execute(getFindByValueCallback( + value.getClass(), value, firstElement, maxElements, Order.asc(orderByAsc))); } - public PaginatedList scrollWithSubclasses(E value, int firstElement, + @SuppressWarnings("unchecked") + public PaginatedList scrollWithSubclasses(E value, int firstElement, int maxElements, String orderByAsc) { validateScrollMethod(value, firstElement, maxElements, orderByAsc); - return (PaginatedList) doGetHibernateTemplate().execute(getFindByValueCallback( - this.supportsClass, false, value, firstElement, maxElements, Order.asc(orderByAsc))); + return (PaginatedList) super.getHibernateTemplate().execute(getFindByValueCallback( + this.supportsClass, value, firstElement, maxElements, Order.asc(orderByAsc))); } - - public PaginatedList scrollPopulated(E value, int firstElement, - int maxElements, String orderByAsc) { - validateScrollMethod(value, firstElement, maxElements, orderByAsc); - return (PaginatedList) doGetHibernateTemplate().execute(getFindByValueCallback( - value.getClass(), true, value, firstElement, maxElements, Order.asc(orderByAsc))); - } - - public PaginatedList scrollPopulatedWithSubclasses(E value, int firstElement, - int maxElements, String orderByAsc) { - validateScrollMethod(value, firstElement, maxElements, orderByAsc); - return (PaginatedList) doGetHibernateTemplate().execute(getFindByValueCallback( - this.supportsClass, true, value, firstElement, maxElements, Order.asc(orderByAsc))); - } private void validateScrollMethod(E value, int firstElement, int MaxElements, String orderByAsc) { Assert.notNull(value); @@ -239,46 +114,14 @@ public class DaoHibernate extends HibernateDaoSuppo public boolean supports(Class clazz) { Assert.notNull(clazz); - return this.supportsClass.equals(clazz); } - public E update(E value) { + public void update(E value) { Assert.notNull(value); - validate(value); - doGetHibernateTemplate().update(value); - - return readId(value.getInternalId()); + super.getHibernateTemplate().update(value); } - /** - * Custom initialization behavior. Called by superclass. - * - * @throws Exception if initialization fails - */ - protected final void initDao() throws Exception { - Assert.notNull(supportsClass, "supportClass is required"); - Assert.notNull(validationManager, "validationManager 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 {} - - public void initialize(Object entity) { - Hibernate.initialize(entity); - } - - public boolean isInitialized(Object entity) { - return Hibernate.isInitialized(entity); - } - /** * Provides a HibernateCallback that will load a list of * objects by a Collection of identities. @@ -313,8 +156,6 @@ public class DaoHibernate extends HibernateDaoSuppo * match, otherwise find by exact match. * * @param whichClass the class (and subclasses) which results will be limited to including - * @param initializeAllProperties indicates whether lazy initialized properties - * should be initialized in the returned results * @param bean bean with the values of the parameters * @param firstElement the first result, numbered from 0 * @param count the maximum number of results @@ -322,15 +163,16 @@ public class DaoHibernate extends HibernateDaoSuppo * * @return a PaginatedList containing the requested objects */ - private HibernateCallback getFindByValueCallback(final Class whichClass, final boolean initializeAllProperties, final Object bean, - final int firstElement, final int count, final Order order) { + private HibernateCallback getFindByValueCallback(final Class whichClass, final Object bean, final int firstElement, final int count, final Order order) { return new HibernateCallback() { - public Object doInHibernate(Session session) + @SuppressWarnings("unchecked") + public Object doInHibernate(Session session) throws HibernateException { - Criteria criteria = session.createCriteria(whichClass); - - criteria.addOrder(order); - + int paramCount = 0; + + StringBuffer queryString = new StringBuffer("from ").append(bean.getClass().getName()).append(" as queryTarget"); + + ClassMetadata classMetadata = getSessionFactory() .getClassMetadata(bean .getClass()); @@ -344,12 +186,6 @@ public class DaoHibernate extends HibernateDaoSuppo /* for each persistent property of the bean */ for (int i = 0; i < propertyNames.length; i++) { String name = propertyNames[i]; - - // Indicate preferred fetching here - if (initializeAllProperties) { - criteria.setFetchMode(name, FetchMode.JOIN); - } - // TODO: Check if EntityMode.POJO appropriate Object value = classMetadata.getPropertyValue(bean, name, EntityMode.POJO); @@ -371,35 +207,47 @@ public class DaoHibernate extends HibernateDaoSuppo continue; } - Type type = classMetadata.getPropertyType(name); - if (name.equals("version")) { continue; } - - if (name.equals("lastUpdatedUsername") || name.equals("lastUpdatedDate")) { - continue; - } - if (type.equals(Hibernate.STRING)) { + Type type = classMetadata.getPropertyType(name); + + if (type.equals(Hibernate.STRING)) { // if the property is mapped as String, find partial match - criteria.add(Expression.ilike(name, - value.toString(), MatchMode.ANYWHERE)); + 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 - criteria.add(Expression.eq(name, value)); + if (paramCount == 0) { + queryString.append(" where "); + } else { + queryString.append(" and "); + } + paramCount++; + queryString.append("queryTarget.").append(name).append(" = " + 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); + + 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); } }; } diff --git a/domain/src/main/java/org/acegisecurity/domain/hibernate/EnumUserType.java b/domain/src/main/java/org/acegisecurity/domain/hibernate/EnumUserType.java index 8678d85f03..f616b90114 100644 --- a/domain/src/main/java/org/acegisecurity/domain/hibernate/EnumUserType.java +++ b/domain/src/main/java/org/acegisecurity/domain/hibernate/EnumUserType.java @@ -22,6 +22,7 @@ import java.sql.SQLException; import java.sql.Types; +import org.acegisecurity.domain.util.GenericsUtils; import org.hibernate.HibernateException; import org.hibernate.usertype.UserType; @@ -32,9 +33,11 @@ import org.hibernate.usertype.UserType; * @version $Id$ */ public class EnumUserType> implements UserType { - private Class clazz = null; - protected EnumUserType(Class c) { - this.clazz = c; + private Class clazz = null; + + @SuppressWarnings("unchecked") + protected EnumUserType() { + this.clazz = GenericsUtils.getGeneric(getClass()); } private static final int[] SQL_TYPES = {Types.VARCHAR}; diff --git a/domain/src/main/java/org/acegisecurity/domain/impl/AbstractPersistableEntity.java b/domain/src/main/java/org/acegisecurity/domain/impl/AbstractPersistableEntity.java index 34afee30bc..3d194f74ec 100644 --- a/domain/src/main/java/org/acegisecurity/domain/impl/AbstractPersistableEntity.java +++ b/domain/src/main/java/org/acegisecurity/domain/impl/AbstractPersistableEntity.java @@ -64,13 +64,4 @@ public abstract class AbstractPersistableEntity extends BusinessObject public int getVersion() { return version; } - - /** - * Sets the version numbers. - * - * @param version the new version number to use - */ - public void setVersion(int version) { - this.version = version; - } } diff --git a/domain/src/main/java/org/acegisecurity/domain/impl/BusinessObject.java b/domain/src/main/java/org/acegisecurity/domain/impl/BusinessObject.java index d2545b16ce..b564ef4fe2 100644 --- a/domain/src/main/java/org/acegisecurity/domain/impl/BusinessObject.java +++ b/domain/src/main/java/org/acegisecurity/domain/impl/BusinessObject.java @@ -51,7 +51,11 @@ public abstract class BusinessObject implements Serializable, Cloneable { * Swallow cloning. * *

- * This method delegates to BeanUtils.cloneBean(). + * 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. *

* * @return a clone of the current instance diff --git a/domain/src/main/java/org/acegisecurity/domain/impl/PersistableEntityInteger.java b/domain/src/main/java/org/acegisecurity/domain/impl/PersistableEntityInteger.java index 8fe08ad00a..df41ca62da 100644 --- a/domain/src/main/java/org/acegisecurity/domain/impl/PersistableEntityInteger.java +++ b/domain/src/main/java/org/acegisecurity/domain/impl/PersistableEntityInteger.java @@ -17,6 +17,7 @@ package org.acegisecurity.domain.impl; import java.io.Serializable; + /** * A persistable entity that uses a Integer based identity. * @@ -26,49 +27,22 @@ import java.io.Serializable; public abstract class PersistableEntityInteger extends AbstractPersistableEntity { //~ Instance fields ======================================================== - protected Integer id; + private Integer id; //~ Methods ================================================================ - /** - * DO NOT USE DIRECTLY. - * - *

- * Typically only used by the persistence layer, but provided with public - * visibility to not limit flexibility. - *

- * - * @param id the new instance identity - */ - public void setId(Integer id) { - this.id = id; - } - /** * Obtains the persistence identity of this instance. - * - *

Marked as abstract to remind users to implement. They'll need to implement - * so their annotations reflect the correct sequence name. */ - public abstract Integer getId(); - + public Integer getId() { + return this.id; + } + /** - * DO NOT USE DIRECTLY. - * - *

- * 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 org.acegisecurity.domain.PersistableEntity} - * interface contract. - *

- * - *

- * Internally delegates to {@link #getId()}. - *

- * - * @return the instance's identity + * Required solely because Hibernate */ public Serializable getInternalId() { - return this.getId(); + return this.id; } + } diff --git a/domain/src/main/java/org/acegisecurity/domain/impl/PersistableEntityLong.java b/domain/src/main/java/org/acegisecurity/domain/impl/PersistableEntityLong.java index 7be2ec5bad..780ecad3a2 100644 --- a/domain/src/main/java/org/acegisecurity/domain/impl/PersistableEntityLong.java +++ b/domain/src/main/java/org/acegisecurity/domain/impl/PersistableEntityLong.java @@ -17,6 +17,7 @@ package org.acegisecurity.domain.impl; import java.io.Serializable; + /** * A persistable entity that uses a Long based identity. * @@ -26,49 +27,23 @@ import java.io.Serializable; public abstract class PersistableEntityLong extends AbstractPersistableEntity { //~ Instance fields ======================================================== - protected Long id; + private Long id; //~ Methods ================================================================ - - /** - * DO NOT USE DIRECTLY. - * - *

- * Typically only used by the persistence layer, but provided with public - * visibility to not limit flexibility. - *

- * - * @param id the new instance identity - */ - public void setId(Long id) { - this.id = id; - } - /** * Obtains the persistence identity of this instance. */ public Long getId() { return this.id; } - + /** - * DO NOT USE DIRECTLY. - * - *

- * 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 org.acegisecurity.domain.PersistableEntity} - * interface contract. - *

- * - *

- * Internally delegates to {@link #getId()}. - *

- * - * @return the instance's identity + * Required solely because Hibernate */ public Serializable getInternalId() { - return this.getId(); + return this.id; } + + } diff --git a/domain/src/main/java/org/acegisecurity/domain/service/ImmutableManager.java b/domain/src/main/java/org/acegisecurity/domain/service/ImmutableManager.java index a35056ae45..734f3da4d5 100644 --- a/domain/src/main/java/org/acegisecurity/domain/service/ImmutableManager.java +++ b/domain/src/main/java/org/acegisecurity/domain/service/ImmutableManager.java @@ -17,6 +17,7 @@ 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; @@ -28,18 +29,16 @@ import java.util.List; * PersistableEntity}, using JDK 1.5 generics. * *

- * This interface provides a remoting protocol compliant approach to accessing - * services layer logic for a given application. A generics-based services - * layer interface decreases development time because the basic CRUD and finder - * operations can be specified in a typesafe fashion that reuses superclass - * code. + * 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. *

* *

* It is not envisioned that this interface will provide all services layer * functions. The significant value of a services layer is the value-add beyond - * simply fronting the DAO or applying validation/binding logic that is better - * situated in the domain object or its validator. The type of value-adds + * 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, @@ -47,17 +46,9 @@ import java.util.List; * 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); making changes to a domain object that requires - * logic that is unsuitable to put into a validator because it extends - * beyond a single domain object instance or requires access to other persistent - * entities (eg computing taxation appliable to an invoice based on a break-down - * of each item on the order, its delivery destination, and the customer); - * 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; expose a reasonably protocol-independent interface - * to the application that can be used by a variety of web services and - * client types; ensure any returned objects are eagerly loaded to a well-defined - * interface contract etc. + * 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. *

* *

@@ -85,7 +76,7 @@ public interface ImmutableManager { * @return all persistence instances (an empty List will be * returned if no matches are found) */ - public List findAll(); + public List findAll() throws DataAccessException; /** * Find a List of PersistableEntitys, searched by @@ -96,7 +87,7 @@ public interface ImmutableManager { * @return the values with those identifiers (an empty List * will be returned if no matches are found) */ - public List findId(Collection ids); + public List findId(Collection ids) throws DataAccessException; /** * Load a persistent instance by its identifier, although some properties @@ -108,19 +99,8 @@ public interface ImmutableManager { * * @return the request item, or null if not found */ - public E readId(Serializable id); + public E readId(Serializable id) throws DataAccessException; - /** - * Loads a persistent instance by its identifier, along with any - * lazy loaded properties associated with that instance. - * - * @param id the identifier of the persistent instance desired to be - * retrieved - * - * @return the request item, or null if not found - */ - public E readPopulatedId(Serializable id); - /** * Find persistent instances with properties matching those of the passed * PersistableEntity. @@ -143,33 +123,7 @@ public interface ImmutableManager { * PaginatedList is returned if no results match) */ public PaginatedList scroll(E value, int firstElement, - int maxElements); - - /** - * Find persistent instances with properties matching those of the passed - * PersistableEntity, with a guarantee the returned results - * will have each of the value class' immediate properties - * initialized. - * - *

- * Persistent instances are matched on the basis of query by example. - * Properties whose value is null, empty - * Strings, and any Collections are ignored in - * the query by example evaluation. - *

- * - * @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 - * PaginatedList is returned if no results match) - */ - public PaginatedList scrollPopulated(E value, int firstElement, - int maxElements); + int maxElements) throws DataAccessException; /** * Find persistent instances with properties matching those of the passed @@ -188,29 +142,8 @@ public interface ImmutableManager { * PaginatedList is returned if no results match) */ public PaginatedList scrollWithSubclasses(E value, int firstElement, - int maxElements); + int maxElements) throws DataAccessException; - /** - * Find persistent instances with properties matching those of the passed - * PersistableEntity, ignoring the class of the passed - * PersistableEntity (useful if you pass a superclass, as you - * want to find all subclass instances which match). Guarantees the returned - * results will have each of the DAO's supports class' immediate - * properties initialized. - * - * @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 - * PaginatedList is returned if no results match) - */ - public PaginatedList scrollPopulatedWithSubclasses(E value, int firstElement, - int maxElements); - /** * Indicates whether the DAO instance provides persistence services for the * specified class. diff --git a/domain/src/main/java/org/acegisecurity/domain/service/ImmutableManagerImpl.java b/domain/src/main/java/org/acegisecurity/domain/service/ImmutableManagerImpl.java index 4ad3521d20..90ec9000cf 100644 --- a/domain/src/main/java/org/acegisecurity/domain/service/ImmutableManagerImpl.java +++ b/domain/src/main/java/org/acegisecurity/domain/service/ImmutableManagerImpl.java @@ -23,8 +23,6 @@ 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.beans.factory.InitializingBean; import org.springframework.context.support.ApplicationObjectSupport; import org.springframework.util.Assert; @@ -34,39 +32,25 @@ import org.springframework.util.Assert; * @author Ben Alex * @version $Id$ */ -public class ImmutableManagerImpl extends ApplicationObjectSupport implements ImmutableManager, InitializingBean { +public class ImmutableManagerImpl extends ApplicationObjectSupport implements ImmutableManager { //~ Instance fields ======================================================== /** The class that this instance provides services for */ private Class supportsClass; - private String beanName; protected Dao dao; //~ Methods ================================================================ - public ImmutableManagerImpl() { + public ImmutableManagerImpl(Dao dao) { + // work out what domain object we support this.supportsClass = GenericsUtils.getGeneric(getClass()); - if (supportsClass == null) { - if (logger.isWarnEnabled()) { - logger.warn("Could not determine the generics type - you will need to set manually"); - } - } - } - - public void setSupportsClass(Class supportClass) { - this.supportsClass = supportClass; - } - - public Class getSupportsClass() { - return supportsClass; - } - - public Dao getDao() { - return dao; - } - - public void setDao(Dao dao) { + 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; } @@ -76,22 +60,6 @@ public class ImmutableManagerImpl extends Applicati protected String getDefaultSortOrder() { return "id"; } - - /** - * Provides hook for custom subclasses to provide initialization behaviour - * - * @throws Exception - */ - protected void doInitManager() throws Exception {} - - public final void afterPropertiesSet() throws Exception { - Assert.notNull(supportsClass, "supportClass is required"); - Assert.isTrue(PersistableEntity.class.isAssignableFrom(supportsClass), - "supportClass is not an implementation of PersistableEntity"); - Assert.notNull(dao, "Dao is null"); - Assert.isTrue(dao.supports(supportsClass), "Dao '" + dao + "' does not support '" + supportsClass + "'"); - doInitManager(); - } public List findAll() { return dao.findAll(); @@ -108,11 +76,6 @@ public class ImmutableManagerImpl extends Applicati return dao.readId(id); } - public E readPopulatedId(Serializable id) { - Assert.notNull(id); - return dao.readPopulatedId(id); - } - public PaginatedList scroll(E value, int firstElement, int maxElements) { Assert.notNull(value); @@ -121,13 +84,6 @@ public class ImmutableManagerImpl extends Applicati return dao.scroll(value, firstElement, maxElements, getDefaultSortOrder()); } - public PaginatedList scrollPopulated(E value, int firstElement, int maxElements) { - Assert.notNull(value); - Assert.isInstanceOf(this.supportsClass, value, "Can only scroll with values this manager supports"); - - return dao.scrollPopulated(value, firstElement, maxElements, getDefaultSortOrder()); - } - public PaginatedList scrollWithSubclasses(E value, int firstElement, int maxElements) { Assert.notNull(value); @@ -136,20 +92,8 @@ public class ImmutableManagerImpl extends Applicati return dao.scrollWithSubclasses(value, firstElement, maxElements, getDefaultSortOrder()); } - public PaginatedList scrollPopulatedWithSubclasses(E value, int firstElement, int maxElements) { - Assert.notNull(value); - Assert.isInstanceOf(this.supportsClass, value, "Can only scroll with values this manager supports"); - - return dao.scrollPopulatedWithSubclasses(value, firstElement, maxElements, getDefaultSortOrder()); - } - public boolean supports(Class clazz) { Assert.notNull(clazz); - return this.supportsClass.equals(clazz); } - - public void setBeanName(String beanName) { - this.beanName = beanName; - } } diff --git a/domain/src/main/java/org/acegisecurity/domain/util/GenericsUtils.java b/domain/src/main/java/org/acegisecurity/domain/util/GenericsUtils.java index 36749b49ef..0121df8e29 100644 --- a/domain/src/main/java/org/acegisecurity/domain/util/GenericsUtils.java +++ b/domain/src/main/java/org/acegisecurity/domain/util/GenericsUtils.java @@ -17,7 +17,7 @@ public class GenericsUtils { * @param clazz The class to introspect * @return the first generic declaration, or null if cannot be determined */ - public static Class getGeneric(Class clazz) { + public static Class getGeneric(Class clazz) { Type genType = clazz.getGenericSuperclass(); if (genType instanceof ParameterizedType) {