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.service.impl;
017:
018: import java.lang.reflect.InvocationTargetException;
019: import java.util.HashMap;
020: import java.util.List;
021: import java.util.Map;
022: import java.util.TreeMap;
023:
024: import org.apache.commons.beanutils.PropertyUtils;
025: import org.kuali.core.bo.DocumentType;
026: import org.kuali.core.service.PersistenceStructureService;
027: import org.kuali.kfs.bo.Options;
028: import org.kuali.kfs.bo.OriginationCode;
029: import org.kuali.module.chart.bo.A21SubAccount;
030: import org.kuali.module.chart.bo.Account;
031: import org.kuali.module.chart.bo.AccountingPeriod;
032: import org.kuali.module.chart.bo.Chart;
033: import org.kuali.module.chart.bo.ObjectCode;
034: import org.kuali.module.chart.bo.ObjectType;
035: import org.kuali.module.chart.bo.ProjectCode;
036: import org.kuali.module.chart.bo.SubAccount;
037: import org.kuali.module.chart.bo.SubObjCd;
038: import org.kuali.module.chart.bo.codes.BalanceTyp;
039: import org.kuali.module.gl.bo.OriginEntry;
040: import org.kuali.module.gl.service.OriginEntryLookupService;
041: import org.kuali.module.gl.util.CachingLookup;
042:
043: /**
044: * This class retrieves the important references related to the OriginEntryFull family of business objects;
045: * it uses a cache to store records its seen before, which hopefully improves performance
046: */
047: public class OriginEntryLookupServiceImpl implements
048: OriginEntryLookupService {
049: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
050: .getLogger(OriginEntryLookupServiceImpl.class);
051:
052: private PersistenceStructureService persistenceStructureService;
053: private ThreadLocal<CachingLookup> localLookupService = new ThreadLocal<CachingLookup>();
054: private Map<String, List> primaryKeyLists = new HashMap<String, List>();
055:
056: /**
057: * Get A21SubAccount for given origin entryable
058: *
059: * @param entry the origin entry to retrieve the A21 sub account of
060: * @return the related A21 SubAccount record, or null if not found
061: * @see org.kuali.module.gl.service.OriginEntryLookupService#getA21SubAccount(org.kuali.module.gl.bo.OriginEntry)
062: */
063: public A21SubAccount getA21SubAccount(OriginEntry entry) {
064: return lookupReference(entry, A21SubAccount.class);
065: }
066:
067: /**
068: * Retrieve account for given origin entry
069: *
070: * @param entry the origin entry to retrieve the account of
071: * @return the related account record, or null if not found
072: * @see org.kuali.module.gl.service.OriginEntryLookupService#getAccount(org.kuali.module.gl.bo.OriginEntry)
073: */
074: public Account getAccount(OriginEntry entry) {
075: return lookupReference(entry, Account.class);
076: }
077:
078: /**
079: * Retrieves the accounting period for the given origin entryable
080: *
081: * @param entry the origin entry to retrieve the accounting period of
082: * @return the related AccountingPeriod record, or null if not found
083: * @see org.kuali.module.gl.service.OriginEntryLookupService#getAccountingPeriod(org.kuali.module.gl.bo.OriginEntry)
084: */
085: public AccountingPeriod getAccountingPeriod(OriginEntry entry) {
086: return lookupReference(entry, AccountingPeriod.class);
087: }
088:
089: /**
090: * Retrieve balance type, or, evidently, balance typ, for given origin entry
091: *
092: * @param entry the origin entry to retrieve the balance type of
093: * @return the related balance typ record, or null if not found
094: * @see org.kuali.module.gl.service.OriginEntryLookupService#getBalanceType(org.kuali.module.gl.bo.OriginEntry)
095: */
096: public BalanceTyp getBalanceType(OriginEntry entry) {
097: return lookupReference(entry, BalanceTyp.class,
098: "code:financialBalanceTypeCode");
099: }
100:
101: /**
102: * Retrieve a chart for the given origin entry
103: *
104: * @param entry the origin entry to get the chart for
105: * @return the related Chart record, or null if not found
106: * @see org.kuali.module.gl.service.OriginEntryLookupService#getChart(org.kuali.module.gl.bo.OriginEntry)
107: */
108: public Chart getChart(OriginEntry entry) {
109: return lookupReference(entry, Chart.class);
110: }
111:
112: /**
113: * Get document type for given origin entryable
114: *
115: * @param entry the origin entry to retrieve the document type of
116: * @return the related document type record, or null if not found
117: * @see org.kuali.module.gl.service.OriginEntryLookupService#getDocumentType(org.kuali.module.gl.bo.OriginEntry)
118: */
119: public DocumentType getDocumentType(OriginEntry entry) {
120: return lookupReference(entry, DocumentType.class);
121: }
122:
123: /**
124: * Get the reference document type for the given origin entryable
125: *
126: * @param entry origin entryable to lookup the reference document type for
127: * @return the related reference DocumentType record, or null if not found
128: * @see org.kuali.module.gl.service.OriginEntryLookupService#getReferenceDocumentType(org.kuali.module.gl.bo.OriginEntry)
129: */
130: public DocumentType getReferenceDocumentType(OriginEntry entry) {
131: return lookupReference(entry, DocumentType.class,
132: "financialDocumentTypeCode:referenceFinancialDocumentTypeCode");
133: }
134:
135: /**
136: * Retrieve financial object for given origin entry
137: *
138: * @param entry the origin entry to retrieve the financial object of
139: * @return the related financial object record, or null if not found
140: * @see org.kuali.module.gl.service.OriginEntryLookupService#getFinancialObject(org.kuali.module.gl.bo.OriginEntry)
141: */
142: public ObjectCode getFinancialObject(OriginEntry entry) {
143: return lookupReference(entry, ObjectCode.class);
144: }
145:
146: /**
147: * Get financial sub object for given origin entryable
148: *
149: * @param entry the origin entry to retrieve the financial sub object of
150: * @return the related financial sub object record, or null if not found
151: * @see org.kuali.module.gl.service.OriginEntryLookupService#getFinancialSubObject(org.kuali.module.gl.bo.OriginEntry)
152: */
153: public SubObjCd getFinancialSubObject(OriginEntry entry) {
154: return lookupReference(entry, SubObjCd.class);
155: }
156:
157: /**
158: * Get object type for given origin entry
159: *
160: * @param entry the origin entry to retrieve the object type of
161: * @return the related object type record, or null if not found
162: * @see org.kuali.module.gl.service.OriginEntryLookupService#getObjectType(org.kuali.module.gl.bo.OriginEntry)
163: */
164: public ObjectType getObjectType(OriginEntry entry) {
165: return lookupReference(entry, ObjectType.class,
166: "code:financialObjectTypeCode");
167: }
168:
169: /**
170: * Retrieve option for given origin entry
171: *
172: * @param entry the origin entry to retrieve the related options record of
173: * @return the related Options record, or null if not found
174: * @see org.kuali.module.gl.service.OriginEntryLookupService#getOption(org.kuali.module.gl.bo.OriginEntry)
175: */
176: public Options getOption(OriginEntry entry) {
177: return lookupReference(entry, Options.class);
178: }
179:
180: /**
181: * Retrieves the origination code for the given origin entryable
182: *
183: * @param entry the origin entry to retrieve the origin code of
184: * @return the related OriginationCode record, or null if not found
185: * @see org.kuali.module.gl.service.OriginEntryLookupService#getOriginationCode(org.kuali.module.gl.bo.OriginEntry)
186: */
187: public OriginationCode getOriginationCode(OriginEntry entry) {
188: return lookupReference(entry, OriginationCode.class,
189: "originationCode:referenceFinancialSystemOriginationCode");
190: }
191:
192: /**
193: * Retrieves the project code for the given origin entryable
194: *
195: * @param entry the origin entry to retrieve the project code of
196: * @return the related ProjectCode record, or null if not found
197: * @see org.kuali.module.gl.service.OriginEntryLookupService#getProjectCode(org.kuali.module.gl.bo.OriginEntry)
198: */
199: public ProjectCode getProjectCode(OriginEntry entry) {
200: return lookupReference(entry, ProjectCode.class,
201: "code:projectCode");
202: }
203:
204: /**
205: * Get sub account for given origin entry
206: *
207: * @param entry the origin entry to retrieve the sub account of
208: * @return the related SubAccount record, or null if not found
209: * @see org.kuali.module.gl.service.OriginEntryLookupService#getSubAccount(org.kuali.module.gl.bo.OriginEntry)
210: */
211: public SubAccount getSubAccount(OriginEntry entry) {
212: return lookupReference(entry, SubAccount.class);
213: }
214:
215: /**
216: * This method takes in an origin entry and returns the primary key map for the related class, based on values of that origin
217: * entry.
218: *
219: * @param entry the entry to perform the lookup on
220: * @param referenceClassToRetrieve the class of a related object
221: * @param fieldNameOverrides if the name of a field in the entry is not the name of the field in a related class, this map can override the entry's field names for the sake of the lookup
222: * @return a Map with the key of the object to lookup in it
223: */
224: private Map<String, Object> getKeyMapFromEntry(OriginEntry entry,
225: Class referenceClassToRetrieve,
226: Map<String, String> fieldNameOverrides) {
227: Map<String, Object> keyMap = new TreeMap<String, Object>();
228:
229: List keyFields = getPrimaryKeyFields(referenceClassToRetrieve);
230: for (Object keyFieldAsObject : keyFields) {
231: String keyField = (String) keyFieldAsObject;
232: String originalKeyField = keyField;
233: if (fieldNameOverrides.containsKey(keyField)) {
234: keyField = fieldNameOverrides.get(keyField);
235: }
236: try {
237: Object property = PropertyUtils.getProperty(entry,
238: keyField);
239: if (property != null) {
240: keyMap.put(originalKeyField, property);
241: } else {
242: keyMap = null;
243: break;
244: }
245: } catch (IllegalAccessException e) {
246: LOG
247: .fatal("Illegal Access Exception trying to access field: "
248: + keyField);
249: throw new RuntimeException(e);
250: } catch (InvocationTargetException e) {
251: LOG
252: .fatal("Illegal Target Exception trying to access field: "
253: + keyField);
254: throw new RuntimeException(e);
255: } catch (NoSuchMethodException e) {
256: LOG
257: .fatal("No such method exception trying to access field: "
258: + keyField);
259: throw new RuntimeException(e);
260: }
261: }
262:
263: return keyMap;
264: }
265:
266: /**
267: * This method looks up a class reference by an origin entry
268: *
269: * @param <T> the class of the object that needs to be looked up
270: * @param entry an entry to perform the lookup on
271: * @param type the class of the related object to lookup
272: * @return the related object or null if not found in the cache or persistence store
273: */
274: private <T> T lookupReference(OriginEntry entry, Class<T> type) {
275: return lookupReference(entry, type, null);
276: }
277:
278: /**
279: * This method looks up a class reference by an origin entry, with certain primary key field names overridden
280: *
281: * @param <T> the class of the object that needs to be looked up
282: * @param entry an entry to perform the lookup on
283: * @param type the class of the related object to lookup
284: * @param fieldNameOverrides if the name of a field in the entry is not the name of the field in a related class, this map can override the entry's field names for the sake of the lookup
285: * @return the related object or null if not found in the cache or persistence store
286: */
287: private <T> T lookupReference(OriginEntry entry, Class<T> type,
288: String fieldNameOverrides) {
289: Map<String, Object> pk = getKeyMapFromEntry(entry, type,
290: convertFieldsToMap(fieldNameOverrides));
291: return (T) localLookupService.get().get(type, pk);
292: }
293:
294: /**
295: * Converts the field name overrides string and turns it into objects
296: *
297: * @param fieldNameOverrides if the name of a field in the entry is not the name of the field in a related class, this map can override the entry's field names for the sake of the lookup
298: * @return a Map where the key is the name of the field in the entry and the value is the name of the field in the related class
299: */
300: private Map<String, String> convertFieldsToMap(
301: String fieldNameOverrides) {
302: Map<String, String> overrides = new HashMap<String, String>();
303: if (fieldNameOverrides != null
304: && fieldNameOverrides.length() > 0) {
305: String[] fieldConversionEntries = fieldNameOverrides
306: .split(";");
307: if (fieldConversionEntries != null
308: && fieldConversionEntries.length > 0) {
309: for (String entry : fieldConversionEntries) {
310: String[] splitEntry = entry.split(":");
311: if (splitEntry != null && splitEntry.length == 2) {
312: overrides.put(splitEntry[0], splitEntry[1]);
313: }
314: }
315: }
316: }
317: return overrides;
318: }
319:
320: /**
321: * This method gets the list of primary key fields for a class, with some caching involved
322: *
323: * @param clazz the class to get primary key fields for
324: * @return a List of String names of the fields for the primary key
325: */
326: private List getPrimaryKeyFields(Class clazz) {
327: List keyFields = primaryKeyLists.get(clazz.getName());
328: if (keyFields == null) {
329: keyFields = persistenceStructureService
330: .listPrimaryKeyFieldNames(clazz);
331: primaryKeyLists.put(clazz.getName(), keyFields);
332: }
333: return keyFields;
334: }
335:
336: /**
337: * Gets the persistenceStructureService attribute.
338: *
339: * @return Returns the persistenceStructureService.
340: */
341: public PersistenceStructureService getPersistenceStructureService() {
342: return persistenceStructureService;
343: }
344:
345: /**
346: * Sets the persistenceStructureService attribute value.
347: *
348: * @param persistenceStructureService The persistenceStructureService to set.
349: */
350: public void setPersistenceStructureService(
351: PersistenceStructureService persistenceStructureService) {
352: this .persistenceStructureService = persistenceStructureService;
353: }
354:
355: /**
356: * Gets the lookupService attribute.
357: *
358: * @return Returns the lookupService.
359: */
360: public CachingLookup getLookupService() {
361: return localLookupService.get();
362: }
363:
364: /**
365: * Sets the lookupService attribute value.
366: *
367: * @param lookupService The lookupService to set.
368: */
369: public void setLookupService(CachingLookup lookupService) {
370: this.localLookupService.set(lookupService);
371: }
372: }
|