Forráskód Böngészése

Refactored. NB: This code is unsupported and illustrates non-anemic domain objects that do not leverage transparent persistence capabilities (I recommend you use transparent persistence capabilities where possible - I hope to check in different packages with new patterns in due course).

Ben Alex 19 éve
szülő
commit
12c78791de

+ 1 - 1
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();
 }

+ 12 - 82
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.
  * </p>
  * 
  * <p>
@@ -67,17 +65,15 @@ public interface Dao<E extends PersistableEntity> {
      * 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<E extends PersistableEntity> {
      * @return all persistence instances (an empty <code>List</code> will be
      *         returned if no matches are found)
      */
-    public List<E> findAll();
+    public List<E> findAll() throws DataAccessException;
 
     /**
      * Find a <code>List</code> of <code>PersistableEntity</code>s, searched by
@@ -96,7 +92,7 @@ public interface Dao<E extends PersistableEntity> {
      * @return the values with those identifiers (an empty <code>List</code>
      *         will be returned if no matches are found)
      */
-    public List<E> findId(Collection<Serializable> ids);
+    public List<E> findId(Collection<Serializable> ids) throws DataAccessException;
 
     /**
      * Load a persistent instance by its identifier, although some properties
@@ -108,19 +104,8 @@ public interface Dao<E extends PersistableEntity> {
      *
      * @return the request item, or <code>null</code> 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 <code>null</code> if not found
-	 */
-	public E readPopulatedId(Serializable id);
-	
     /**
      * Find persistent instances with properties matching those of the passed
      * <code>PersistableEntity</code>.
@@ -146,36 +131,7 @@ public interface Dao<E extends PersistableEntity> {
      *         <code>PaginatedList</code> is returned if no results match)
      */
     public PaginatedList<E> scroll(E value, int firstElement,
-        int maxElements, String orderByAsc);
-
-    /**
-     * Find persistent instances with properties matching those of the passed
-     * <code>PersistableEntity</code>, with a guarantee the returned results
-     * will have each of the <code>value</code> class' immediate properties
-     * initialized.
-     * 
-     * <P>
-     * Persistent instances are matched on the basis of query by example.
-     * Properties whose value is <code>null</code>, empty
-     * <code>String</code>s, and any <code>Collection</code>s are ignored in
-     * the query by example evaluation.
-     * </p>
-     *
-     * @param value parameters to filter on (the class of this object will
-     * be added to the filter)
-     * @param firstElement the first result (start at zero to obtain all
-     *        results)
-     * @param maxElements the maximum number of results desired for this page
-     *        of the result set
-     * @param orderByAsc the property name of the
-     *        <code>PersistableEntity</code> that should be used to order the
-     *        results
-     *
-     * @return the requested page of the result list (a properly formed
-     *         <code>PaginatedList</code> is returned if no results match)
-     */
-    public PaginatedList<E> 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<E extends PersistableEntity> {
      *         <code>PaginatedList</code> is returned if no results match)
 	 */
     public PaginatedList<E> scrollWithSubclasses(E value, int firstElement,
-	        int maxElements, String orderByAsc);
-
-	/**
-     * Find persistent instances with properties matching those of the passed
-     * <code>PersistableEntity</code>, ignoring the class of the passed
-     * <code>PersistableEntity</code> (useful if you pass a superclass, as you
-     * want to find all subclass instances which match). Guarantees the returned 
-     * results will have each of the DAO's <code>supports</code> 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
-     *        <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<E> 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<E extends PersistableEntity> {
      *
      * @param value to update, with the <code>PersistableEntity</code> having a
      *        non-<code>null</code> identifier
-     *
-     * @return the updated value
      */
-    public E update(E value);
+    public void update(E value) throws DataAccessException;
 }

+ 68 - 220
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,181 +45,66 @@ import org.springframework.validation.BindException;
  * @author Matthew Porter
  * @version $Id$
  */
-public class DaoHibernate<E extends PersistableEntity> extends HibernateDaoSupport implements Dao<E>,
-    EvictionCapable, InitializationCapable {
+public class DaoHibernate<E extends PersistableEntity> extends HibernateDaoSupport implements Dao<E> {
     //~ 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 <code>HibernateTemplate</code> that uses the appropriate <code>Session</code>
-	 * based on the value of {@link DetachmentContextHolder}.
-	 * 
-	 * <p>Specifically, if <code>DetachmentContextHolder</code> requires detached instances,
-	 * the method will build a new <code>Session</code> (ignore the current thread-bound
-	 * <code>Session</code>) and use that new <code>Session</code> in the <code>HibernateTemplate</code>.
-	 * If <code>DetachmentContextHolder</code> is at its fault <code>false</code> value, the
-	 * returned <code>HibernateTemplate</code> will simply use the <code>Session</code> obtained
-	 * from the superclass, which is generally the same <code>Session</code> as used for the
-	 * transaction.
-	 * 
-	 * @return the template, containing the correct <code>Session</code> based on the
-	 * <code>DetachmentContactHolder</code> 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<E> findAll() {
+        return super.getHibernateTemplate().loadAll(supportsClass);
     }
 
-    public List<E> findAll() {
-        return doGetHibernateTemplate().loadAll(supportsClass);
-    }
-
-    public List<E> findId(Collection<Serializable> ids) {
+    @SuppressWarnings("unchecked")
+	public List<E> findId(Collection<Serializable> ids) {
         Assert.notNull(ids, "Collection of IDs cannot be null");
         Assert.notEmpty(ids, "There must be some values in the Collection list");
 
-        return (List) doGetHibernateTemplate().execute(getFindByIdCallback(ids));
-    }
-
-    private E readId(final Serializable id, final boolean populate) {
-        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 (List) super.getHibernateTemplate().execute(getFindByIdCallback(ids));
     }
 
-    public E readId(Serializable id) {
+    @SuppressWarnings("unchecked")
+	public E readId(Serializable id) {
         Assert.notNull(id);
-		return readId(id, false);
+        return (E) getHibernateTemplate().load(supportsClass, id);
     }
 
-	public E readPopulatedId(Serializable id) {
-        Assert.notNull(id);
-        return readId(id, true);
-	}
-	
-	/**
-	 * Locates every <code>get*()</code> method against the passed entity
-	 * and calls it. This method does not nest its initialization beyond
-	 * the immediately passed entity.
-	 * 
-	 * <p>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<E> scroll(E value, int firstElement,
+    @SuppressWarnings("unchecked")
+	public PaginatedList<E> 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<E> 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)));
-	    }
-	
-    public PaginatedList<E> scrollPopulated(E value, int firstElement,
+    @SuppressWarnings("unchecked")
+	public PaginatedList<E> scrollWithSubclasses(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)));
+	        return (PaginatedList) super.getHibernateTemplate().execute(getFindByValueCallback(
+	                this.supportsClass, value, firstElement, maxElements, Order.asc(orderByAsc)));
 	    }
 
-	public PaginatedList<E> 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);
         Assert.hasText(orderByAsc,
@@ -239,46 +114,14 @@ public class DaoHibernate<E extends PersistableEntity> 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());
-    }
-
-    /**
-     * 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();
+        super.getHibernateTemplate().update(value);
     }
 
-    /**
-     * 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 <code>HibernateCallback</code> that will load a list of
      * objects by a <code>Collection</code> of identities.
@@ -313,8 +156,6 @@ public class DaoHibernate<E extends PersistableEntity> 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<E extends PersistableEntity> 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<E extends PersistableEntity> 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<E extends PersistableEntity> 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<E> list = criteria.setFirstResult(firstElement).setMaxResults(count).list();
-
-                    return new PaginatedList<E>(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);
                 }
             };
     }

+ 6 - 3
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<E extends Enum<E>> implements UserType { 
-    private Class<E> clazz = null; 
-    protected EnumUserType(Class<E> c) { 
-        this.clazz = c; 
+    private Class<E> clazz = null;
+    
+    @SuppressWarnings("unchecked")
+	protected EnumUserType() { 
+		this.clazz = GenericsUtils.getGeneric(getClass());
     } 
  
     private static final int[] SQL_TYPES = {Types.VARCHAR}; 

+ 0 - 9
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;
-    }
 }

+ 5 - 1
domain/src/main/java/org/acegisecurity/domain/impl/BusinessObject.java

@@ -51,7 +51,11 @@ public abstract class BusinessObject implements Serializable, Cloneable {
      * Swallow cloning.
      * 
      * <p>
-     * 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.
      * </p>
      *
      * @return a clone of the current instance

+ 9 - 35
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 <code>Integer</code> 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.
-     * 
-     * <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.
-     * 
-     * <p>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.
-     * 
-     * <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 org.acegisecurity.domain.PersistableEntity}
-     * interface contract.
-     * </p>
-     * 
-     * <p>
-     * Internally delegates to {@link #getId()}.
-     * </p>
-     *
-     * @return the instance's identity
+     * Required solely because Hibernate
      */
     public Serializable getInternalId() {
-        return this.getId();
+    	return this.id;
     }
+
 }

+ 7 - 32
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 <code>Long</code> 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.
-     * 
-     * <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.
      */
     public Long getId() {
     	return this.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 org.acegisecurity.domain.PersistableEntity}
-     * interface contract.
-     * </p>
-     * 
-     * <p>
-     * Internally delegates to {@link #getId()}.
-     * </p>
-     *
-     * @return the instance's identity
+     * Required solely because Hibernate
      */
     public Serializable getInternalId() {
-        return this.getId();
+    	return this.id;
     }
+
+
 }

+ 14 - 81
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.
  * 
  * <P>
- * 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.
  * </p>
  * 
  * <p>
  * It is not envisioned that this interface will provide <b>all</b> services layer
  * functions. The significant value of a services layer is the value-add beyond
- * simply fronting the DAO 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.
  * </p>
  * 
  * <P>
@@ -85,7 +76,7 @@ public interface ImmutableManager<E extends PersistableEntity> {
      * @return all persistence instances (an empty <code>List</code> will be
      *         returned if no matches are found)
      */
-    public List<E> findAll();
+    public List<E> findAll() throws DataAccessException;
 
     /**
      * Find a <code>List</code> of <code>PersistableEntity</code>s, searched by
@@ -96,7 +87,7 @@ public interface ImmutableManager<E extends PersistableEntity> {
      * @return the values with those identifiers (an empty <code>List</code>
      *         will be returned if no matches are found)
      */
-    public List<E> findId(Collection<Serializable> ids);
+    public List<E> findId(Collection<Serializable> ids) throws DataAccessException;
 
     /**
      * Load a persistent instance by its identifier, although some properties
@@ -108,19 +99,8 @@ public interface ImmutableManager<E extends PersistableEntity> {
      *
      * @return the request item, or <code>null</code> 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 <code>null</code> if not found
-	 */
-	public E readPopulatedId(Serializable id);
-	
     /**
      * Find persistent instances with properties matching those of the passed
      * <code>PersistableEntity</code>.
@@ -143,33 +123,7 @@ public interface ImmutableManager<E extends PersistableEntity> {
      *         <code>PaginatedList</code> is returned if no results match)
      */
     public PaginatedList<E> scroll(E value, int firstElement,
-        int maxElements);
-
-    /**
-     * Find persistent instances with properties matching those of the passed
-     * <code>PersistableEntity</code>, with a guarantee the returned results
-     * will have each of the <code>value</code> class' immediate properties
-     * initialized.
-     * 
-     * <P>
-     * Persistent instances are matched on the basis of query by example.
-     * Properties whose value is <code>null</code>, empty
-     * <code>String</code>s, and any <code>Collection</code>s are ignored in
-     * the query by example evaluation.
-     * </p>
-     *
-     * @param value parameters to filter on (the class of this object will
-     * be added to the filter)
-     * @param firstElement the first result (start at zero to obtain all
-     *        results)
-     * @param maxElements the maximum number of results desired for this page
-     *        of the result set
-     *
-     * @return the requested page of the result list (a properly formed
-     *         <code>PaginatedList</code> is returned if no results match)
-     */
-    public PaginatedList<E> 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<E extends PersistableEntity> {
      *         <code>PaginatedList</code> is returned if no results match)
 	 */
     public PaginatedList<E> scrollWithSubclasses(E value, int firstElement,
-	        int maxElements);
+	        int maxElements) throws DataAccessException;
 
-	/**
-     * Find persistent instances with properties matching those of the passed
-     * <code>PersistableEntity</code>, ignoring the class of the passed
-     * <code>PersistableEntity</code> (useful if you pass a superclass, as you
-     * want to find all subclass instances which match). Guarantees the returned 
-     * results will have each of the DAO's <code>supports</code> 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
-     *         <code>PaginatedList</code> is returned if no results match)
-	 */
-    public PaginatedList<E> scrollPopulatedWithSubclasses(E value, int firstElement,
-	        int maxElements);
-	
 	/**
      * Indicates whether the DAO instance provides persistence services for the
      * specified class.

+ 9 - 65
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<E extends PersistableEntity> extends ApplicationObjectSupport implements ImmutableManager<E>, InitializingBean {
+public class ImmutableManagerImpl<E extends PersistableEntity> extends ApplicationObjectSupport implements ImmutableManager<E> {
     //~ Instance fields ========================================================
 
     /** The class that this instance provides services for */
     private Class supportsClass;
-	private String beanName;
 	
 	protected Dao<E> dao;
 
     //~ Methods ================================================================
 	
-	public ImmutableManagerImpl() {
+	public ImmutableManagerImpl(Dao<E> 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<E> getDao() {
-		return dao;
-	}
-
-	public void setDao(Dao<E> 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<E extends PersistableEntity> 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<E> findAll() {
         return dao.findAll();
@@ -108,11 +76,6 @@ public class ImmutableManagerImpl<E extends PersistableEntity> extends Applicati
         return dao.readId(id);
     }
 
-    public E readPopulatedId(Serializable id) {
-		Assert.notNull(id);
-		return dao.readPopulatedId(id);
-	}
-
 	public PaginatedList<E> scroll(E value, int firstElement,
         int maxElements) {
         Assert.notNull(value);
@@ -121,13 +84,6 @@ public class ImmutableManagerImpl<E extends PersistableEntity> extends Applicati
         return dao.scroll(value, firstElement, maxElements, getDefaultSortOrder());
     }
 
-    public PaginatedList<E> 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<E> scrollWithSubclasses(E value, int firstElement,
 	        int maxElements) {
 	        Assert.notNull(value);
@@ -136,20 +92,8 @@ public class ImmutableManagerImpl<E extends PersistableEntity> extends Applicati
 	        return dao.scrollWithSubclasses(value, firstElement, maxElements, getDefaultSortOrder());
 	    }
 
-	public PaginatedList<E> 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;
-	}
 }

+ 1 - 1
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 <code>null</code> if cannot be determined
      */
-    public static Class getGeneric(Class clazz) {
+	public static Class getGeneric(Class clazz) {
         Type genType = clazz.getGenericSuperclass();
 
         if (genType instanceof ParameterizedType) {