001: /*
002: * Copyright 2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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: */
016: package org.kuali.module.gl.util;
017:
018: import java.util.HashSet;
019: import java.util.LinkedHashMap;
020: import java.util.Map;
021: import java.util.Set;
022:
023: import org.kuali.core.bo.PersistableBusinessObject;
024: import org.kuali.core.service.BusinessObjectService;
025:
026: /**
027: * This class wraps BusinessObjectService, in that it takes a class and a key and looks up the associated business object class.
028: * However, it also caches everything as it finds it or does not find it. It also never flushes; so, this is only appropriate for
029: * use in situations where the looked up business objects are guaranteed to survive the lifetime of the using class.
030: */
031: public class CachingLookup {
032: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
033: .getLogger(CachingLookup.class);
034:
035: private int cacheSize = 7500;
036: private Map<String, PersistableBusinessObject> whitelist;
037: private Set<String> blacklist;
038: private BusinessObjectService businessObjectService;
039:
040: /**
041: * Constructs a CachingLookup
042: */
043: public CachingLookup() {
044: float hashTableLoadFactor = 0.75f;
045: int hashTableCapacity = (int) Math.ceil(cacheSize
046: / hashTableLoadFactor) + 1;
047: whitelist = new LinkedHashMap<String, PersistableBusinessObject>(
048: hashTableCapacity, hashTableLoadFactor, true) {
049: private static final long serialVersionUID = 1;
050:
051: @Override
052: protected boolean removeEldestEntry(
053: Map.Entry<String, PersistableBusinessObject> eldest) {
054: return size() > CachingLookup.this .cacheSize;
055: }
056: };
057: blacklist = new HashSet<String>();
058: }
059:
060: /**
061: * This method looks up and returns a persistable business object, based on its class and keys
062: *
063: * @param boClass the class of the PersistableBusinessObject descendant to return
064: * @param key the primary key for that class
065: * @return the persistable business object
066: */
067: public PersistableBusinessObject get(Class boClass, Map key) {
068: if (boClass == null || key == null || key.size() == 0) {
069: return null;
070: }
071: String cacheKey = convertClassAndPKToCacheKey(boClass, key);
072: if (blacklist.contains(cacheKey)) {
073: return null;
074: } else if (whitelist.containsKey(cacheKey)) {
075: return whitelist.get(cacheKey);
076: } else {
077: PersistableBusinessObject result = businessObjectService
078: .findByPrimaryKey(boClass, key);
079: if (result == null) {
080: LOG.debug("Could not find record for BO of class: "
081: + boClass.getName() + " keys: "
082: + key.toString());
083: blacklist.add(cacheKey);
084: } else {
085: whitelist.put(cacheKey, result);
086: }
087: return result;
088: }
089: }
090:
091: /**
092: * This method takes a class and a key to look up that class and turns it into the key format that the cache is using
093: *
094: * @param boClass class of the business object to cache
095: * @param key the primary key of the business object to look up
096: * @return a string with the cache key
097: */
098: private String convertClassAndPKToCacheKey(Class boClass, Map key) {
099: StringBuilder cacheKey = new StringBuilder();
100: cacheKey.append(boClass.getName());
101: cacheKey.append("|");
102: cacheKey.append(key.toString());
103: return cacheKey.toString();
104: }
105:
106: /**
107: * Gets the businessObjectService attribute.
108: *
109: * @return Returns the businessObjectService.
110: */
111: public BusinessObjectService getBusinessObjectService() {
112: return businessObjectService;
113: }
114:
115: /**
116: * Sets the businessObjectService attribute value.
117: *
118: * @param businessObjectService The businessObjectService to set.
119: */
120: public void setBusinessObjectService(
121: BusinessObjectService businessObjectService) {
122: this .businessObjectService = businessObjectService;
123: }
124:
125: /**
126: * Gets the cacheSize attribute.
127: *
128: * @return Returns the cacheSize.
129: */
130: public int getCacheSize() {
131: return cacheSize;
132: }
133:
134: /**
135: * Sets the cacheSize attribute value.
136: *
137: * @param cacheSize The cacheSize to set.
138: */
139: public void setCacheSize(int cacheSize) {
140: this.cacheSize = cacheSize;
141: }
142: }
|