001/* 002 * Copyright 2009 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.ole.sys.batch.service; 017 018import java.util.HashMap; 019import java.util.LinkedHashMap; 020import java.util.Map; 021 022import org.kuali.ole.gl.businessobject.AccountBalance; 023import org.kuali.rice.krad.bo.BusinessObject; 024import org.kuali.rice.krad.bo.PersistableBusinessObjectBase; 025import org.springframework.transaction.annotation.Transactional; 026 027/** 028 * This class CANNOT be used by 2 processes simultaneously. It is for very specific batch processes that should not run at the same 029 * time, and initialize and destroy must be called and the beginning and end of each process that uses it. 030 */ 031@Transactional 032public abstract class AbstractBatchTransactionalCachingService implements WrappingBatchService { 033 protected Map<String,BusinessObject> referenceValueCache; 034 protected Map<Class,PreviousValueReference> previousValueCache; 035 036 public void initialize() { 037 referenceValueCache = new HashMap<String,BusinessObject>(); 038 previousValueCache = new HashMap<Class,PreviousValueReference>(); 039 } 040 041 public void destroy() { 042 referenceValueCache = null; 043 previousValueCache = null; 044 } 045 046 static final class NonExistentReferenceBusinessObject extends PersistableBusinessObjectBase { 047 048 protected LinkedHashMap toStringMapper_RICE20_REFACTORME() { 049 throw new UnsupportedOperationException(); 050 } 051 } 052 protected static final BusinessObject NON_EXISTENT_REFERENCE_CACHE_VALUE = new NonExistentReferenceBusinessObject(); 053 protected String getCacheKey(Class clazz, Object...objects) { 054 StringBuffer cacheKey = new StringBuffer(clazz.getName()); 055 for (int i = 0; i < objects.length; i++) { 056 cacheKey.append("-").append(objects[i]); 057 } 058 return cacheKey.toString(); 059 } 060 protected abstract class ReferenceValueRetriever<T extends BusinessObject> { 061 public T get(Class<T> type, Object...keys) { 062 String cacheKey = getCacheKey(type, keys); 063 BusinessObject businessObject = referenceValueCache.get(cacheKey); 064 if (businessObject == null) { 065 try { 066 businessObject = useDao(); 067 } 068 catch (Exception e) { 069 throw new RuntimeException("Unable to getBusinessObject in AccountingCycleCachingServiceImpl: " + cacheKey, e); 070 } 071 if (businessObject == null) { 072 referenceValueCache.put(cacheKey, NON_EXISTENT_REFERENCE_CACHE_VALUE); 073 } 074 else { 075 referenceValueCache.put(cacheKey, businessObject); 076 retrieveReferences((T)businessObject); 077 } 078 } 079 else if (businessObject instanceof NonExistentReferenceBusinessObject) { 080 businessObject = null; 081 } 082 return (T)businessObject; 083 } 084 protected abstract T useDao(); 085 protected abstract void retrieveReferences(T object); 086 } 087 public class PreviousValueReference<T extends BusinessObject> { 088 protected String key = ""; 089 protected T value; 090 public T getValue() { 091 return value; 092 } 093 public void update(T value, String key) { 094 this.key = key; 095 this.value = value; 096 } 097 public void update(T value, Object...keys) { 098 update (value, getCacheKey(value.getClass(), keys)); 099 } 100 } 101 protected abstract class PreviousValueRetriever<T extends BusinessObject> { 102 public T get(Class<T> type, Object...keys) { 103 String cacheKey = getCacheKey(type, keys); 104 if (!cacheKey.equals(previousValueCache.get(AccountBalance.class).key.equals(cacheKey))) { 105 previousValueCache.get(type).update(useDao(), cacheKey); 106 } 107 return (T)previousValueCache.get(type).getValue(); 108 } 109 protected abstract T useDao(); 110 } 111}