All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sakaiproject.genericdao.base.BaseGenericDao Maven / Gradle / Ivy

Go to download

Generic Dao is a Java package which allows a developer to skip writing DAOs for their persistence objects when they are using Spring and/or Hibernate. The package was originally created by Aaron Zeckoski for the Evaluation System project but was repackaged to make it distributable by request. It is used in the RSF framework (http://www2.caret.cam.ac.uk/rsfwiki/). Note about the BeanUtils provided dependency: BeanUtils is not required if you are not using it in your project. Note about the Hibernate provided dependency: Hibernate is not required if you are not using it in your project.

The newest version!
/**
 * $Id$
 * $URL$
 * JdbcGenericDao.java - genericdao - Apr 18, 2008 10:07:08 AM - azeckoski
 **************************************************************************
 * Copyright (c) 2008 Aaron Zeckoski
 * Licensed under the Apache License, Version 2
 * 
 * A copy of the Apache License, Version 2 has been included in this 
 * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 * Aaron Zeckoski ([email protected]) ([email protected]) ([email protected])
 */

package org.sakaiproject.genericdao.base;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.azeckoski.reflectutils.ReflectUtils;
import org.sakaiproject.genericdao.api.GenericDao;
import org.sakaiproject.genericdao.api.caching.CacheProvider;
import org.sakaiproject.genericdao.api.interceptors.DaoOperationInterceptor;
import org.sakaiproject.genericdao.api.interceptors.ReadInterceptor;
import org.sakaiproject.genericdao.api.interceptors.WriteInterceptor;
import org.sakaiproject.genericdao.api.search.Search;
import org.sakaiproject.genericdao.base.caching.NonCachingCacheProvider;

/**
 * This is the simple base implementation which includes shared methods and should be extended,
 * this handles the caching checks and the interceptors on the basic methods
 * 
 * @author Aaron Zeckoski ([email protected])
 */
public abstract class BaseGenericDao implements GenericDao {

   /**
    * MUST be overridden
    */
   protected  T baseFindById(Class type, Serializable id) {
       throw new UnsupportedOperationException("Not Implemented");
   }

   /**
    * MUST be overridden
    */
   protected Serializable baseCreate(Class type, Object object) {
       throw new UnsupportedOperationException("Not Implemented");
   }

   /**
    * MUST be overridden
    */
   protected void baseUpdate(Class type, Object id, Object object) {
       throw new UnsupportedOperationException("Not Implemented");
   }

   /**
    * MUST be overridden
    */
   protected  boolean baseDelete(Class type, Serializable id) {
       throw new UnsupportedOperationException("Not Implemented");
   }

   /**
    * Get the id value from a persistent object,
    * this expects that the object is persistent so it should already be checked
* Override this if desired * @param entity any persistent object * @return the id value or null if it is unset */ protected Serializable baseGetIdValue(Object entity) { Class type = findClass(entity); String idProp = getIdProperty(type); Object idValue = null; if (idProp == null) { throw new IllegalArgumentException("Could not find id property for this class type: " + type); } else { idValue = ReflectUtils.getInstance().getFieldValue(entity, idProp); } Serializable serialId = null; if (idValue != null) { if (! (idValue instanceof Serializable)) { serialId = idValue.toString(); } } return serialId; } /** * Find the class type of a persistent object, * needed in the case that we are working with something that wraps it's objects
* Override this if desired * @param entity a persistent entity * @return the persistent class type OR null if it cannot be found */ protected Class findClass(Object entity) { if (entity == null) { throw new IllegalArgumentException("Cannot find class type of null entity object"); } Class type = entity.getClass(); return type; } // COMMON CODE private List> classes; protected void setClasses(List> classes) { this.classes = classes; } /** * This does a nice bit of exception handling for us and verifies that * this class is valid to perform a DAO operation with * @param type class type of the persistent object to check * @return A valid entityClass type resolved to be the same as * the ones usable by this DAO */ protected Class checkClass(Class type) { if (type == null) { throw new NullPointerException("type cannot be null"); } if (classes == null) { throw new NullPointerException("persistent classes must be set"); } for (Iterator> i = classes.iterator(); i.hasNext();) { Class concrete = (Class) i.next(); if (concrete.isAssignableFrom(type)) { return concrete; } } throw new IllegalArgumentException("Could not resolve this class " + type + " as part of the set of persistent objects: " + classes.toString()); } private CacheProvider cacheProvider; /** * @return the current cache provider */ protected CacheProvider getCacheProvider() { if (cacheProvider == null) { cacheProvider = new NonCachingCacheProvider(); } return cacheProvider; } /** * Set the cache provider to an implementation of {@link CacheProvider}, * this will be set to {@link NonCachingCacheProvider} if this is not set explicitly * @param cacheProvider */ public void setCacheProvider(CacheProvider cacheProvider) { this.cacheProvider = cacheProvider; } /** * @return the cache name used for storing this type of persistent object */ protected String getCacheName(Class type) { if (type == null) { throw new IllegalArgumentException("type cannot be null"); } return type.getName(); } /** * @return the cachename used for storing search results for this type of object */ protected String getSearchCacheName(Class type) { if (type == null) { throw new IllegalArgumentException("type cannot be null"); } return "search:" + type.getName(); } /** * Creates all the caches for the current set of persistent types, * this should be called in the init for the generic dao being used after persistent classes are loaded */ protected void initCaches() { for (Class type : classes) { getCacheProvider().createCache(getCacheName(type)); getCacheProvider().createCache(getSearchCacheName(type)); } } // INTERCEPTOR methods private Map, ReadInterceptor> readInterceptors = new ConcurrentHashMap, ReadInterceptor>(); private Map, WriteInterceptor> writeInterceptors = new ConcurrentHashMap, WriteInterceptor>(); /** * Adds the provided interceptor to the current set of interceptors * @param interceptor */ public void addInterceptor(DaoOperationInterceptor interceptor) { if (interceptor != null) { Class type = interceptor.interceptType(); if (type != null) { if (ReadInterceptor.class.isAssignableFrom(interceptor.getClass())) { readInterceptors.put(type, (ReadInterceptor) interceptor); } if (WriteInterceptor.class.isAssignableFrom(interceptor.getClass())) { writeInterceptors.put(type, (WriteInterceptor) interceptor); } } } } /** * Removes the provided interceptor from the current set of interceptors * @param interceptor */ public void removeInterceptor(DaoOperationInterceptor interceptor) { if (interceptor != null) { Class type = interceptor.interceptType(); if (type != null) { if (ReadInterceptor.class.isAssignableFrom(interceptor.getClass())) { readInterceptors.remove(type); } if (WriteInterceptor.class.isAssignableFrom(interceptor.getClass())) { writeInterceptors.remove(type); } } } } /** * Makes the given interceptor the only active interceptor, * removes all others and adds only this one * @param interceptor */ public void setInterceptor(DaoOperationInterceptor interceptor) { if (interceptor != null) { readInterceptors.clear(); writeInterceptors.clear(); addInterceptor(interceptor); } } protected void beforeRead(String operation, Class type, Serializable[] ids, Search search) { if (type != null) { ReadInterceptor interceptor = readInterceptors.get(type); if (interceptor != null) { interceptor.beforeRead(operation, ids, search); } } } protected void afterRead(String operation, Class type, Serializable[] ids, Search search, Object[] entities) { if (type != null) { ReadInterceptor interceptor = readInterceptors.get(type); if (interceptor != null) { interceptor.afterRead(operation, ids, search, entities); } } } protected void beforeWrite(String operation, Class type, Serializable[] ids, Object[] entities) { if (type != null) { WriteInterceptor interceptor = writeInterceptors.get(type); if (interceptor != null) { interceptor.beforeWrite(operation, ids, entities); } } } protected void afterWrite(String operation, Class type, Serializable[] ids, Object[] entities, int changes) { if (type != null) { WriteInterceptor interceptor = writeInterceptors.get(type); if (interceptor != null) { interceptor.afterWrite(operation, ids, entities, changes); } } } // ********* PUBLIC methods **************** /* (non-Javadoc) * @see org.sakaiproject.genericdao.api.GenericDao#getPersistentClasses() */ public List> getPersistentClasses() { return new ArrayList>(classes); } /* (non-Javadoc) * @see org.sakaiproject.genericdao.api.GenericDao#invokeTransactionalAccess(java.lang.Runnable) */ public void invokeTransactionalAccess(Runnable toinvoke) { toinvoke.run(); } /* (non-Javadoc) * @see org.sakaiproject.genericdao.api.GenericDao#findById(java.lang.Class, java.io.Serializable) */ @SuppressWarnings("unchecked") public T findById(Class type, Serializable id) { checkClass(type); if (id == null) { throw new IllegalArgumentException("id must be set to find persistent object"); } T entity = null; // check cache first String key = id.toString(); String cacheName = getCacheName(type); if (getCacheProvider().exists(cacheName, key)) { entity = (T) getCacheProvider().get(cacheName, key); } else { // not in cache so go to the DB // before interceptor String operation = "findById"; beforeRead(operation, type, new Serializable[] {id}, null); entity = baseFindById(type, id); // now put the item in the cache getCacheProvider().put(cacheName, key, entity); // after interceptor afterRead(operation, type, new Serializable[] {id}, null, new Object[] {entity}); } return entity; } /* (non-Javadoc) * @see org.sakaiproject.genericdao.api.modifiers.BasicModifier#create(java.lang.Object) */ public void create(Object object) { Class type = findClass(object); checkClass(type); String operation = "create"; beforeWrite(operation, type, null, new Object[] {object}); Serializable idValue = baseCreate(type, object); // clear the search caches getCacheProvider().clear(getSearchCacheName(type)); afterWrite(operation, type, new Serializable[] {idValue}, new Object[] {object}, 1); } /* (non-Javadoc) * @see org.sakaiproject.genericdao.api.modifiers.BasicModifier#update(java.lang.Object) */ public void update(Object object) { Class type = findClass(object); checkClass(type); Serializable idValue = baseGetIdValue(object); if (idValue == null) { throw new IllegalArgumentException("Could not get an id value from the supplied object, cannot update without an id: " + object); } String operation = "update"; beforeWrite(operation, type, new Serializable[] {idValue}, new Object[] {object}); baseUpdate(type, idValue, object); // clear the search caches getCacheProvider().clear(getSearchCacheName(type)); // clear the cache entry since this was updated String key = idValue.toString(); String cacheName = getCacheName(type); getCacheProvider().remove(cacheName, key); afterWrite(operation, type, new Serializable[] {idValue}, new Object[] {object}, 1); } /* (non-Javadoc) * @see org.sakaiproject.genericdao.api.modifiers.BasicModifier#save(java.lang.Object) */ public void save(Object object) { Serializable id = baseGetIdValue(object); if (id == null) { create(object); } else { update(object); } } /* (non-Javadoc) * @see org.sakaiproject.genericdao.api.modifiers.BasicModifier#delete(java.lang.Object) */ public void delete(Object object) { Class type = findClass(object); Serializable id = baseGetIdValue(object); delete(type, id); } /* (non-Javadoc) * @see org.sakaiproject.genericdao.api.modifiers.BasicModifier#delete(java.lang.Class, java.io.Serializable) */ public boolean delete(Class type, Serializable id) { checkClass(type); String operation = "delete"; beforeWrite(operation, type, new Serializable[] {id}, null); boolean removed = baseDelete(type, id); if (removed) { // clear the search caches getCacheProvider().clear(getSearchCacheName(type)); // clear this from the cache String key = id.toString(); String cacheName = getCacheName(type); getCacheProvider().remove(cacheName, key); afterWrite(operation, type, new Serializable[] {id}, null, 1); } return removed; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy