瀏覽代碼

Refactor lifecycle methods into separate files, so that subclasses can extend specific classes or interfaces to achieve the desired subset of lifecycle capabilities.

Ben Alex 20 年之前
父節點
當前提交
1455029435

+ 38 - 0
domain/src/main/java/org/acegisecurity/domain/service/CreatableManager.java

@@ -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.service;
+
+import net.sf.acegisecurity.domain.PersistableEntity;
+
+/**
+ * Adds a creation method to the <code>ImmutableManager</code>.
+ * 
+ * @author Ben Alex
+ * @version $Id$
+ */
+public interface CreatableManager<E extends PersistableEntity> extends ImmutableManager<E> {
+    //~ 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 E create(E value);
+}

+ 36 - 0
domain/src/main/java/org/acegisecurity/domain/service/CreatableManagerImpl.java

@@ -0,0 +1,36 @@
+/* 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.service;
+
+import net.sf.acegisecurity.domain.PersistableEntity;
+
+import org.springframework.util.Assert;
+
+/**
+ * Base {@link CreatableManager} implementation.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class CreatableManagerImpl<E extends PersistableEntity> extends ImmutableManagerImpl<E> implements CreatableManager<E> {
+	public E create(E value) {
+        Assert.notNull(value);
+		if (logger.isDebugEnabled()) {
+			logger.debug("Creating: " + value);
+		}
+        return dao.create(value);
+    }
+}

+ 226 - 0
domain/src/main/java/org/acegisecurity/domain/service/ImmutableManager.java

@@ -0,0 +1,226 @@
+/* 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.service;
+
+import net.sf.acegisecurity.domain.PersistableEntity;
+import net.sf.acegisecurity.domain.dao.PaginatedList;
+
+import java.io.Serializable;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Provides fundamental services layer capabilities for a single concrete {@link
+ * PersistableEntity}, using JDK 1.5 generics.
+ * 
+ * <P>
+ * 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.
+ * </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
+ * expected to be provided by a services layer include incrementing business
+ * identifiers (eg an invoice number); generating messages for logging/audit
+ * purposes (thus such messages are at a business transaction level of granularity,
+ * instead of DAO/persistence granularity where the overall context of the
+ * the message becomes unclear); updating related domain objects via
+ * their respective services layer beans (eg an invoice services layer bean
+ * would call the general journal services layer bean to create the accrual
+ * accounting entries); 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.
+ * </p>
+ * 
+ * <P>
+ * A single <code>ImmutableManager</code> implementation will typically exist for each
+ * {@link net.sf.acegisecurity.domain.PersistableEntity}, particularly given
+ * a <code>PersistableEntity</code> is allowed to manage multiple
+ * {@link net.sf.acegisecurity.domain.impl.PersistableValue}s.
+ * The particular <code>PersistableEntity</code> an implementation supports
+ * will be expressed by the {@link #supports(Class)} method.
+ * </p>
+ * 
+ * <p>No other part of the Domain subproject relies on this interface. If
+ * you would prefer to write your own services layer interfaces from scratch,
+ * this is not a problem at all.
+ * 
+ * @author Ben Alex
+ * @version $Id$
+ */
+public interface ImmutableManager<E extends PersistableEntity> {
+    //~ Methods ================================================================
+
+    /**
+     * Return all persistent instances, including subclasses.
+     *
+     * @return all persistence instances (an empty <code>List</code> will be
+     *         returned if no matches are found)
+     */
+    public List<E> 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<E> findId(Collection<Serializable> ids);
+
+    /**
+     * Load a persistent instance by its identifier, although some properties
+     * may be lazy loaded depending on the underlying DAO implementation and/or
+     * persistence engine mapping document.
+     *
+     * @param id the identifier of the persistent instance desired to be
+     *        retrieved
+     *
+     * @return the request item, or <code>null</code> if not found
+     */
+    public E readId(Serializable id);
+
+	/**
+	 * 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>.
+     * 
+     * <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> 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);
+
+	/**
+     * Find persistent instances with properties matching those of the passed
+     * <code>PersistableEntity</code>, ignoring the class of the passed
+     * <code>PersistableEntity</code> (useful if you pass a superclass, as you
+     * want to find all subclass instances which match).
+	 * 
+     * @param value parameters to filter on (the class of this object will
+     * NOT be added to the filter)
+     * @param firstElement the first result (start at zero to obtain all
+     *        results)
+     * @param maxElements the maximum number of results desired for this page
+     *        of the result set
+     *
+     * @return the requested page of the result list (a properly formed
+     *         <code>PaginatedList</code> is returned if no results match)
+	 */
+    public PaginatedList<E> scrollWithSubclasses(E value, int firstElement,
+	        int maxElements);
+
+	/**
+     * 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.
+     *
+     * @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);
+
+}

+ 155 - 0
domain/src/main/java/org/acegisecurity/domain/service/ImmutableManagerImpl.java

@@ -0,0 +1,155 @@
+/* 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.service;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+
+import net.sf.acegisecurity.domain.PersistableEntity;
+import net.sf.acegisecurity.domain.dao.Dao;
+import net.sf.acegisecurity.domain.dao.PaginatedList;
+import net.sf.acegisecurity.domain.util.GenericsUtils;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.support.ApplicationObjectSupport;
+import org.springframework.util.Assert;
+
+/**
+ * Base {@link ImmutableManager} implementation.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class ImmutableManagerImpl<E extends PersistableEntity> extends ApplicationObjectSupport implements ImmutableManager<E>, InitializingBean {
+    //~ Instance fields ========================================================
+
+    /** The class that this instance provides services for */
+    private Class supportsClass;
+	private String beanName;
+	
+	protected Dao<E> dao;
+
+    //~ Methods ================================================================
+	
+	public ImmutableManagerImpl() {
+		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) {
+		this.dao = dao;
+	}
+
+	/**
+	 * @return the sort order column to be used by default by the scroll methods
+	 */
+	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();
+    }
+
+    public List<E> findId(Collection<Serializable> ids) {
+        Assert.notNull(ids, "Collection of IDs cannot be null");
+        Assert.notEmpty(ids, "There must be some values in the Collection list");
+        return dao.findId(ids);
+    }
+
+    public E readId(Serializable id) {
+        Assert.notNull(id);
+        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);
+		Assert.isInstanceOf(this.supportsClass, value, "Can only scroll with values this manager supports");
+
+        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);
+			Assert.isInstanceOf(this.supportsClass, value, "Can only scroll with values this manager supports");
+
+	        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;
+	}
+}

+ 3 - 233
domain/src/main/java/org/acegisecurity/domain/service/Manager.java

@@ -16,250 +16,20 @@
 package net.sf.acegisecurity.domain.service;
 
 import net.sf.acegisecurity.domain.PersistableEntity;
-import net.sf.acegisecurity.domain.dao.PaginatedList;
-
-import java.io.Serializable;
-
-import java.util.Collection;
-import java.util.List;
 
 /**
- * Provides fundamental services layer capabilities for a single concrete {@link
- * PersistableEntity}, using JDK 1.5 generics.
- * 
- * <P>
- * 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.
- * </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
- * expected to be provided by a services layer include incrementing business
- * identifiers (eg an invoice number); generating messages for logging/audit
- * purposes (thus such messages are at a business transaction level of granularity,
- * instead of DAO/persistence granularity where the overall context of the
- * the message becomes unclear); updating related domain objects via
- * their respective services layer beans (eg an invoice services layer bean
- * would call the general journal services layer bean to create the accrual
- * accounting entries); 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.
- * </p>
- * 
- * <P>
- * A single <code>Manager</code> implementation will typically exist for each
- * {@link net.sf.acegisecurity.domain.PersistableEntity}, particularly given
- * a <code>PersistableEntity</code> is allowed to manage multiple
- * {@link net.sf.acegisecurity.domain.impl.PersistableValue}s.
- * The particular <code>PersistableEntity</code> an implementation supports
- * will be expressed by the {@link #supports(Class)} method.
- * </p>
- * 
- * <p>No other part of the Domain subproject relies on this interface. If
- * you would prefer to write your own services layer interfaces from scratch,
- * this is not a problem at all.
+ * Adds a deletion method to <code>UpdatableManager</code>, thus providing CRUD
+ * use case support.
  * 
  * @author Ben Alex
  * @version $Id$
  */
-public interface Manager<E extends PersistableEntity> {
+public interface Manager<E extends PersistableEntity> extends UpdatableManager<E> {
     //~ 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 E create(E 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 E createOrUpdate(E value);
-
     /**
      * Delete an object.
      *
      * @param value the value to delete
      */
     public void delete(E value);
-
-    /**
-     * Return all persistent instances, including subclasses.
-     *
-     * @return all persistence instances (an empty <code>List</code> will be
-     *         returned if no matches are found)
-     */
-    public List<E> 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<E> findId(Collection<Serializable> ids);
-
-    /**
-     * Load a persistent instance by its identifier, although some properties
-     * may be lazy loaded depending on the underlying DAO implementation and/or
-     * persistence engine mapping document.
-     *
-     * @param id the identifier of the persistent instance desired to be
-     *        retrieved
-     *
-     * @return the request item, or <code>null</code> if not found
-     */
-    public E readId(Serializable id);
-
-	/**
-	 * 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>.
-     * 
-     * <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> 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);
-
-	/**
-     * Find persistent instances with properties matching those of the passed
-     * <code>PersistableEntity</code>, ignoring the class of the passed
-     * <code>PersistableEntity</code> (useful if you pass a superclass, as you
-     * want to find all subclass instances which match).
-	 * 
-     * @param value parameters to filter on (the class of this object will
-     * NOT be added to the filter)
-     * @param firstElement the first result (start at zero to obtain all
-     *        results)
-     * @param maxElements the maximum number of results desired for this page
-     *        of the result set
-     *
-     * @return the requested page of the result list (a properly formed
-     *         <code>PaginatedList</code> is returned if no results match)
-	 */
-    public PaginatedList<E> scrollWithSubclasses(E value, int firstElement,
-	        int maxElements);
-
-	/**
-     * 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.
-     *
-     * @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 E update(E value);
 }

+ 1 - 160
domain/src/main/java/org/acegisecurity/domain/service/ManagerImpl.java

@@ -15,18 +15,8 @@
 
 package net.sf.acegisecurity.domain.service;
 
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.List;
-
 import net.sf.acegisecurity.domain.PersistableEntity;
-import net.sf.acegisecurity.domain.dao.Dao;
-import net.sf.acegisecurity.domain.dao.PaginatedList;
-import net.sf.acegisecurity.domain.util.GenericsUtils;
 
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.context.support.ApplicationObjectSupport;
-import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.Assert;
 
 /**
@@ -35,89 +25,7 @@ import org.springframework.util.Assert;
  * @author Ben Alex
  * @version $Id$
  */
-@Transactional
-public class ManagerImpl<E extends PersistableEntity> extends ApplicationObjectSupport implements Manager<E>, InitializingBean {
-    //~ Instance fields ========================================================
-
-    /** The class that this instance provides services for */
-    private Class supportsClass;
-	private String beanName;
-	
-	protected Dao<E> dao;
-
-    //~ Methods ================================================================
-	
-	public ManagerImpl() {
-		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) {
-		this.dao = dao;
-	}
-
-	/**
-	 * @return the sort order column to be used by default by the scroll methods
-	 */
-	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 E create(E value) {
-        Assert.notNull(value);
-		if (logger.isDebugEnabled()) {
-			logger.debug("Creating: " + value);
-		}
-        return dao.create(value);
-    }
-
-	/**
-	 * Delegates to the appropriate services layer method (not the DAO).
-	 */
-    public E createOrUpdate(E value) {
-        Assert.notNull(value);
-		if (logger.isDebugEnabled()) {
-			logger.debug("CreatingOrUpdating: " + value);
-		}
-		if (value.getInternalId() == null) {
-			return create(value);
-		} else {
-			return update(value);
-		}
-    }
-
+public class ManagerImpl<E extends PersistableEntity> extends UpdatableManagerImpl<E> implements Manager<E> {
     public void delete(E value) {
         Assert.notNull(value);
 		if (logger.isDebugEnabled()) {
@@ -126,71 +34,4 @@ public class ManagerImpl<E extends PersistableEntity> extends ApplicationObjectS
         dao.delete(value);
     }
 
-    public List<E> findAll() {
-        return dao.findAll();
-    }
-
-    public List<E> findId(Collection<Serializable> ids) {
-        Assert.notNull(ids, "Collection of IDs cannot be null");
-        Assert.notEmpty(ids, "There must be some values in the Collection list");
-        return dao.findId(ids);
-    }
-
-    public E readId(Serializable id) {
-        Assert.notNull(id);
-        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);
-		Assert.isInstanceOf(this.supportsClass, value, "Can only scroll with values this manager supports");
-
-        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);
-			Assert.isInstanceOf(this.supportsClass, value, "Can only scroll with values this manager supports");
-
-	        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 E update(E value) {
-        Assert.notNull(value);
-		if (logger.isDebugEnabled()) {
-			logger.debug("Updating: " + value);
-		}
-        return dao.update(value);
-    }
-
-	public void setBeanName(String beanName) {
-		this.beanName = beanName;
-	}
 }

+ 51 - 0
domain/src/main/java/org/acegisecurity/domain/service/UpdatableManager.java

@@ -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.service;
+
+import net.sf.acegisecurity.domain.PersistableEntity;
+
+/**
+ * Adds update (but no delete) methods to the <code>CreatableManager</code>.
+ * 
+ * @author Ben Alex
+ * @version $Id$
+ */
+public interface UpdatableManager<E extends PersistableEntity> extends CreatableManager<E> {
+    //~ Methods ================================================================
+
+	/**
+     * 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 E createOrUpdate(E value);
+
+    /**
+     * Update an object.
+     *
+     * @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);
+}

+ 52 - 0
domain/src/main/java/org/acegisecurity/domain/service/UpdatableManagerImpl.java

@@ -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.service;
+
+import net.sf.acegisecurity.domain.PersistableEntity;
+
+import org.springframework.util.Assert;
+
+/**
+ * Base {@link UpdatableManager} implementation.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class UpdatableManagerImpl<E extends PersistableEntity> extends CreatableManagerImpl<E> implements UpdatableManager<E> {
+
+    public E update(E value) {
+        Assert.notNull(value);
+		if (logger.isDebugEnabled()) {
+			logger.debug("Updating: " + value);
+		}
+        return dao.update(value);
+    }
+    
+    /**
+	 * Delegates to the appropriate services layer method (not the DAO).
+	 */
+    public E createOrUpdate(E value) {
+        Assert.notNull(value);
+		if (logger.isDebugEnabled()) {
+			logger.debug("CreatingOrUpdating: " + value);
+		}
+		if (value.getInternalId() == null) {
+			return create(value);
+		} else {
+			return update(value);
+		}
+    }
+}