package com.joe.utilities.core.lookup; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; import org.springframework.context.ApplicationContext; import com.joe.utilities.core.configuration.admin.domain.IApplicationConfiguration; import com.joe.utilities.core.hibernate.repository.ApplicationConfigurationRepository; import com.joe.utilities.core.hibernate.repository.LookupRepository; import com.joe.utilities.core.serviceLocator.ServiceLocator; import com.joe.utilities.core.util.ILookupProfile; import com.joe.utilities.core.util.IStandardFieldLookupProfile; /** * This class manages the retrieval and caching of lookup data that resides in database. * * @author John J. Jones III, Dave Ousey * @version 1.0 * * Creation date: Dec 15, 2004 4:12:50 PM Copyright (c) 2004 MEDecision, Inc. All rights reserved. */ public class LookupManager implements DisposableBean { /** Name of class. Used for cache and map keys. */ public static final String NAME = LookupManager.class.getName(); /** Reference to class singleton */ private static LookupManager singletonInstance; /** Reference to log for this class */ private static Log log = LogFactory.getLog(LookupManager.class); /** Group name for domain entries in CacheManager */ public static final String LOOKUP_GROUP_CACHE_NAME = "lookupProfileGroup"; public static final String APPLICATION_CONFIG_GROUP_CACHE_NAME = "appConfigGroup"; public static final String DEFAULT_MCO_ID = "MDL"; /** * Method getInstance. Returns existing singleton instance of class or returns new class if one does not exist. * * @return LookupManager */ public static LookupManager getInstance() { if (singletonInstance == null) { singletonInstance = new LookupManager(); } return singletonInstance; } @Autowired private ApplicationContext applicationContext; private LookupRepository lookupRepository; private ApplicationConfigurationRepository applicationConfigRepo; /** * */ private LookupManager() { } /** * Method getLookupProfile. Returns ILookupProfile object from cached items. * * @param mcoID * @param lookupClassName * @param itemCode * @return Cachable */ public ILookupProfile getLookupProfile(String mcoID, String lookupClassName, String itemCode) { if (log.isDebugEnabled()) log.debug("getLookupProfile: " + lookupClassName + "." + itemCode); return getLookupMap(mcoID, lookupClassName).get(itemCode); } /** * getLookupProfile * * @param lookupClassName * @param itemCode * @return ILookupProfile */ public ILookupProfile getLookupProfile(String lookupClassName, String itemCode) { return getLookupProfile(DEFAULT_MCO_ID, lookupClassName, itemCode); } /** * Method getDescription. Returns description for specified ILookupProfile * * @param mcoID * @param lookupClassName * @param itemCode * @return String */ public String getLookupDescription(String mcoID, String lookupClassName, String itemCode) { ILookupProfile theItem = getLookupProfile(mcoID, lookupClassName, itemCode); if (theItem != null) return theItem.getDescription(); else return null; } /** * getLookupDescription * * @param lookupClassName * @param itemCode * @return String */ public static String getLookupDescription(String lookupClassName, String itemCode) { return getInstance().getLookupDescription(DEFAULT_MCO_ID, lookupClassName, itemCode); } /** * Method getLookupMap. Returns map of domain items for simple domain table. * * @param mcoID * @param lookupClassName * @return Map<String, ILookupProfile> */ public Map<String, ILookupProfile> getLookupMap(String mcoID, String lookupClassName) { if (mcoID == null || mcoID.length() == 0) throw new IllegalArgumentException("Null MCO ID passed to LookupManager processing."); if (lookupClassName == null || lookupClassName.length() == 0) throw new IllegalArgumentException("Null domain name passed to LookupManager processing."); // Get the cache entry for this domain Map<String, ILookupProfile> lookupMap = (Map<String, ILookupProfile>) CacheManager.getFromCache(mcoID, NAME + '.' + lookupClassName); if (lookupMap == null) lookupMap = retrieveLookupList(lookupClassName, mcoID); // Return all items return lookupMap; } /** * Method getLookupMap. Returns map of domain items for simple domain table. * * @param lookupClassName * @return Map<String, ILookupProfile> */ public Map<String, ILookupProfile> getLookupMap(String lookupClassName) { return getLookupMap(DEFAULT_MCO_ID, lookupClassName); } /** * getLookupList * * @param lookupClassName * @return List<ILookupProfile> */ public static List<ILookupProfile> getLookupList(String lookupClassName) { return getSortedLookupList(DEFAULT_MCO_ID, lookupClassName); } /** * Method retrieveLookup. Retrieves domain items from database and sets to cache. * * @param lookupClassName * @param mcoID */ private Map<String, ILookupProfile> retrieveLookupList(String lookupClassName, String mcoID) { LookupRepository lookupRepository = getLookupRepository(); List<ILookupProfile> lookupList = lookupRepository.getLookupList(lookupClassName); // Construct the map Map<String, ILookupProfile> simpleMap = new HashMap<String, ILookupProfile>(lookupList.size()); // Populate with data from the database for (ILookupProfile lookup : lookupList) { simpleMap.put(lookup.getCode(), lookup); } // Add map to MCO's domain cache CacheManager.putInCache(mcoID, NAME + '.' + lookupClassName, simpleMap, LOOKUP_GROUP_CACHE_NAME); return simpleMap; } /** * Method getStandardFieldLookupMap. Returns map of domain items for simple domain table. * * @param mcoID * @param lookupClassName * @return Map<String, IStandardFieldLookupProfile> */ public Map<String, IStandardFieldLookupProfile> getStandardFieldLookupMap(String mcoID, String lookupClassName) { if (mcoID == null || mcoID.length() == 0) throw new IllegalArgumentException("Null MCO ID passed to LookupManager processing."); if (lookupClassName == null || lookupClassName.length() == 0) throw new IllegalArgumentException("Null domain name passed to LookupManager processing."); // Get the cache entry for this domain Map<String, IStandardFieldLookupProfile> lookupMap = (Map<String, IStandardFieldLookupProfile>) CacheManager .getFromCache(mcoID, NAME + '.' + lookupClassName); if (lookupMap == null) lookupMap = retrieveStandardFieldLookupList(lookupClassName, mcoID); // Return all items return lookupMap; } /** * Method getStandardFieldLookupMap. Returns map of domain items for simple domain table. * * @param lookupClassName * @return Map<String, IStandardFieldLookupProfile> */ public Map<String, IStandardFieldLookupProfile> getStandardFieldLookupMap(String lookupClassName) { return getStandardFieldLookupMap(DEFAULT_MCO_ID, lookupClassName); } /** * getLookupList * * @param lookupClassName * @return List<IStandardFieldLookupProfile> */ public static List<IStandardFieldLookupProfile> getStandardFieldLookupList(String lookupClassName) { return getSortedStandardFieldLookupList(DEFAULT_MCO_ID, lookupClassName); } /** * Method getSortedStandardFieldLookupList. * * @param mcoID * @param lookupClassName * @return List<IStandardFieldLookupProfile> */ public static List<IStandardFieldLookupProfile> getSortedStandardFieldLookupList(String mcoID, String lookupClassName) { return getSortedStandardFieldLookupList(getInstance().getStandardFieldLookupMap(mcoID, lookupClassName)); } /** * Method getSortedLookupList. * * @param lookupMap * @return List<ILookupProfile> */ public static List<IStandardFieldLookupProfile> getSortedStandardFieldLookupList( Map<String, IStandardFieldLookupProfile> lookupMap) { List<IStandardFieldLookupProfile> sortedILookupProfiles = new ArrayList<IStandardFieldLookupProfile>( lookupMap.values()); Collections.sort(sortedILookupProfiles, new Comparator<IStandardFieldLookupProfile>() { public int compare(IStandardFieldLookupProfile lookup1, IStandardFieldLookupProfile lookup2) { if (lookup1.getDescription().equalsIgnoreCase(lookup2.getDescription())) return 1; else return lookup1.getDescription().compareToIgnoreCase(lookup2.getDescription()); } }); return sortedILookupProfiles; } /** * Method getSortedStandardFieldLookupList. * * @param lookupClassName * @return List<IStandardFieldLookupProfile> */ public static List<IStandardFieldLookupProfile> getSortedStandardFieldLookupList(String lookupClassName) { return getSortedStandardFieldLookupList(DEFAULT_MCO_ID, lookupClassName); } /** * Method retrieveStandardFieldLookup. Retrieves domain items from database and sets to cache. * * @param lookupClassName * @param mcoID */ private Map<String, IStandardFieldLookupProfile> retrieveStandardFieldLookupList( String standardFieldLookupClassName, String mcoID) { LookupRepository lookupRepository = getLookupRepository(); List<IStandardFieldLookupProfile> lookupList = lookupRepository .getStandardFieldLookupList(standardFieldLookupClassName); // Construct the map Map<String, IStandardFieldLookupProfile> simpleMap = new HashMap<String, IStandardFieldLookupProfile>( lookupList.size()); // Populate with data from the database for (IStandardFieldLookupProfile lookup : lookupList) { simpleMap.put(lookup.getCode(), lookup); } // Add map to MCO's domain cache CacheManager.putInCache(mcoID, NAME + '.' + standardFieldLookupClassName, simpleMap, LOOKUP_GROUP_CACHE_NAME); return simpleMap; } /** * Method isValidLookupProfile. * * @param mcoID * @param lookupClassName * @param code * @return boolean */ public static boolean isValidLookupProfile(String mcoID, String lookupClassName, String code) { return null != getInstance().getLookupProfile(mcoID, lookupClassName, code); } /** * isValidLookupProfile * * @param lookupClassName * @param code * @return boolean */ public static boolean isValidLookupProfile(String lookupClassName, String code) { return isValidLookupProfile(DEFAULT_MCO_ID, lookupClassName, code); } /** * Method flushMCOLookup. Flush all domain table entries for the given MCO. * * @param mcoID */ public static void flushMCOLookup(String mcoID) { CacheManager.flushGroup(mcoID, LOOKUP_GROUP_CACHE_NAME); CacheManager.flushGroup(mcoID, APPLICATION_CONFIG_GROUP_CACHE_NAME); } /** * Method setTestLookupMap. Allows test processing to set a domain map into the LookupManager cache as an * alternative to the domain values in the current database. * * @param mcoID * @param lookupClassName * @param lookupMap */ public static void setTestLookupMap(String mcoID, String lookupClassName, Map<String, ILookupProfile> lookupMap) { // Validate that MCO ID = "GNL". Must only be used for test purposes if (!"GNL".equals(mcoID)) throw new IllegalArgumentException( "Cannot call LookupManager's setTestLookupMap method outside of JUnit test code with MCO ID = 'GNL'."); // Validate that OP is valued if (lookupClassName == null) throw new IllegalArgumentException( "Null domain name parameter passed to 'setTestLookupMap' method of LookupManager."); // Flush any existing entry CacheManager.flushItem(mcoID, NAME + '.' + lookupClassName); // Place new entry CacheManager.putInCache(mcoID, NAME + '.' + lookupClassName, lookupMap, LOOKUP_GROUP_CACHE_NAME); } /** * Method getSortedLookupList. * * @param mcoID * @param lookupClassName * @return List<ILookupProfile> */ public static List<ILookupProfile> getSortedLookupList(String mcoID, String lookupClassName) { return getSortedLookupList(getInstance().getLookupMap(mcoID, lookupClassName)); } /** * Method getSortedLookupList. * * @param lookupClassName * @return List<ILookupProfile> */ public static List<ILookupProfile> getSortedLookupList(String lookupClassName) { return getSortedLookupList(DEFAULT_MCO_ID, lookupClassName); } /** * Method getSortedLookupList. * * @param lookupMap * @return List<ILookupProfile> */ public static List<ILookupProfile> getSortedLookupList(Map<String, ILookupProfile> lookupMap) { List<ILookupProfile> sortedILookupProfiles = new ArrayList<ILookupProfile>(lookupMap.values()); Collections.sort(sortedILookupProfiles, new Comparator<ILookupProfile>() { public int compare(ILookupProfile lookup1, ILookupProfile lookup2) { if (lookup1.getDescription().equalsIgnoreCase(lookup2.getDescription())) return 1; else return lookup1.getDescription().compareToIgnoreCase(lookup2.getDescription()); } }); return sortedILookupProfiles; } /** * getApplicationConfiguration * * @param configurationName * @return IApplicationConfiguration */ public static IApplicationConfiguration getApplicationConfiguration(String configurationName) { return getInstance().getApplicationConfiguration(DEFAULT_MCO_ID, configurationName); } /** * getApplicationConfiguration * * @param mcoID * @param configurationName * @return IApplicationConfiguration */ private IApplicationConfiguration getApplicationConfiguration(String mcoID, String configurationName) { if (mcoID == null || mcoID.length() == 0) throw new IllegalArgumentException("Null MCO ID passed to LookupManager processing."); if (configurationName == null || configurationName.length() == 0) throw new IllegalArgumentException("Null app configuration name passed to LookupManager processing."); // Get the cache entry for this domain IApplicationConfiguration appConfiguration = (IApplicationConfiguration) CacheManager.getFromCache(mcoID, NAME + ".appconfig." + configurationName); if (appConfiguration == null) appConfiguration = retrieveApplicaitonConfiguration(mcoID, configurationName); // Return all items return appConfiguration; } /** * retrieveApplicaitonConfiguration * * @param configurationName * @return IApplicationConfiguration */ private IApplicationConfiguration retrieveApplicaitonConfiguration(String mcoID, String configurationName) { ApplicationConfigurationRepository acr = getAppConfigurationRepository(); IApplicationConfiguration ac = acr.retreiveApplicationConfigProperty(configurationName); // Add map to MCO's domain cache if (ac != null) CacheManager.putInCache(mcoID, NAME + ".appconfig." + configurationName, ac, APPLICATION_CONFIG_GROUP_CACHE_NAME); return ac; } /** * @return */ private ApplicationConfigurationRepository getAppConfigurationRepository() { /* * hack: if this bean wasn't wired by spring, use ServiceLocator */ if (this.applicationContext == null) { return (ApplicationConfigurationRepository) ServiceLocator.getInstance().getBean( "applicationConfigRepository"); } else { return this.applicationConfigRepo; } } /*** * Lookup an {@link IProfile} instance and properly cast it to the appropriate type. * * @param <T> * The class type * @param clazz * The class which you are trying to lookup * @param code * The code which you are looking up * @return The instance, or null */ public <T extends ILookupProfile> T lookup(Class<T> clazz, String code) { return (T) getLookupProfile(clazz.getName(), code); } /** * Hack for figuring out if this bean was loaded via Spring * * @return */ private LookupRepository getLookupRepository() { /* * hack: if this bean wasn't wired by spring, use ServiceLocator */ if (this.applicationContext == null) { // execute resource call to retrieve table contents ServiceLocator svcLocator = ServiceLocator.getInstance(); // Call lookup repository return (LookupRepository) svcLocator.getBean("lookupRepository"); } else { return lookupRepository; } } @Required public void setLookupRepository(LookupRepository lookupRepository) { this.lookupRepository = lookupRepository; } @Required public void setApplicationConfigRepo(ApplicationConfigurationRepository applicationConfigRepo) { this.applicationConfigRepo = applicationConfigRepo; } /** * @formatter:off * Workaround for some unit tests. * * The workaround is needed because {@link LookupManager} is loaded two ways: * 1. wired via Spring * 2. manually constructed using {@link LookupManager#getInstance()} * * If you do (1) first and then try (2), then {@link LookupManager#applicationContext} will not be null, and * then tests that use a mock {@link ServiceLocator} will fail because {@link LookupManager#applicationContext} will not be null * * @see org.springframework.beans.factory.DisposableBean#destroy() */ @Override public void destroy() throws Exception { setApplicationConfigRepo(null); this.applicationContext = null; setApplicationConfigRepo(null); } }