From 0425724b4ff9d2dd521b16586f8800c3b23bfe4e Mon Sep 17 00:00:00 2001 From: Ben Alex Date: Tue, 10 May 2005 03:21:36 +0000 Subject: [PATCH] Add services layer generics to Domain subproject. --- .classpath | 4 +- .../acegisecurity/domain/service/Manager.java | 205 ++++++++++++++++++ .../domain/service/ManagerImpl.java | 155 +++++++++++++ project.xml | 2 +- 4 files changed, 363 insertions(+), 3 deletions(-) create mode 100644 domain/src/main/java/org/acegisecurity/domain/service/Manager.java create mode 100644 domain/src/main/java/org/acegisecurity/domain/service/ManagerImpl.java diff --git a/.classpath b/.classpath index fc141f452b..bb4a5974ea 100644 --- a/.classpath +++ b/.classpath @@ -120,11 +120,11 @@ - + - + diff --git a/domain/src/main/java/org/acegisecurity/domain/service/Manager.java b/domain/src/main/java/org/acegisecurity/domain/service/Manager.java new file mode 100644 index 0000000000..79e507bbea --- /dev/null +++ b/domain/src/main/java/org/acegisecurity/domain/service/Manager.java @@ -0,0 +1,205 @@ +/* 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. + * + *

+ * 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. + *

+ * + *

+ * 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 + * 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. + *

+ * + *

+ * A single Manager implementation will typically exist for each + * {@link net.sf.acegisecurity.domain.PersistableEntity}, particularly given + * a PersistableEntity is allowed to manage multiple + * {@link net.sf.acegisecurity.domain.impl.PersistableValue}s. + * The particular PersistableEntity an implementation supports + * will be expressed by the {@link #supports(Class)} method. + *

+ * + *

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 Manager { + //~ 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-null + * 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 List will be + * returned if no matches are found) + */ + public List findAll(); + + /** + * Find a List of PersistableEntitys, searched by + * their identifiers. + * + * @param ids collection of identifiers to locate + * + * @return the values with those identifiers (an empty List + * will be returned if no matches are found) + */ + public List findId(Collection ids); + + /** + * Load a persistent instance by its identifier. + * + * @param id the identifier of the persistent instance desired to be + * retrieved + * + * @return the request item, or null if not found + */ + public E readId(Serializable id); + + /** + * Find persistent instances with properties matching those of the passed + * PersistableEntity. + * + *

+ * 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 scroll(E value, int firstElement, + int maxElements); + + /** + * 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). + * + * @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 scrollWithSubclasses(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 + * PersistableEntity + * + * @return true or false, 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 PersistableEntity having a + * non-null identifier + * + * @return the updated value + */ + public E update(E value); +} diff --git a/domain/src/main/java/org/acegisecurity/domain/service/ManagerImpl.java b/domain/src/main/java/org/acegisecurity/domain/service/ManagerImpl.java new file mode 100644 index 0000000000..a7264ea0a9 --- /dev/null +++ b/domain/src/main/java/org/acegisecurity/domain/service/ManagerImpl.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 org.springframework.beans.factory.InitializingBean; +import org.springframework.context.support.ApplicationObjectSupport; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; + +/** + * Base {@link Manager} implementation. + * + * @author Ben Alex + * @version $Id$ + */ +@Transactional +public class ManagerImpl extends ApplicationObjectSupport implements Manager, InitializingBean { + //~ Instance fields ======================================================== + + /** The class that this instance provides services for */ + private Class supportsClass; + + protected Dao dao; + + //~ Methods ================================================================ + + public void setSupportsClass(Class supportClass) { + this.supportsClass = supportClass; + } + + public Class getSupportsClass() { + return supportsClass; + } + + public Dao getDao() { + return dao; + } + + public void setDao(Dao 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); + } + + public E createOrUpdate(E value) { + Assert.notNull(value); + if (logger.isDebugEnabled()) { + logger.debug("CreatingOrUpdating: " + value); + } + return dao.createOrUpdate(value); + } + + public void delete(E value) { + Assert.notNull(value); + if (logger.isDebugEnabled()) { + logger.debug("Deleting: " + value); + } + dao.delete(value); + } + + public List findAll() { + return dao.findAll(); + } + + 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 dao.findId(ids); + } + + public E readId(Serializable id) { + Assert.notNull(id); + return dao.readId(id); + } + + public PaginatedList 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 scrollWithSubclasses(E value, int firstElement, + int maxElements) { + Assert.notNull(value); + Assert.isInstanceOf(this.supportsClass, value, "Can only scroll with values this manager supports"); + + return dao.scrollWithSubclasses(value, firstElement, maxElements, getDefaultSortOrder()); + } + + public boolean supports(Class clazz) { + Assert.notNull(clazz); + + return this.supportsClass.equals(clazz); + } + + public E update(E value) { + Assert.notNull(value); + if (logger.isDebugEnabled()) { + logger.debug("Updating: " + value); + } + return dao.update(value); + } +} diff --git a/project.xml b/project.xml index 8e55b4198c..b4a43c926a 100644 --- a/project.xml +++ b/project.xml @@ -248,7 +248,7 @@ springframework spring - 1.2-SNAPSHOT + 1.2-rc2 jar http://www.springframework.org