001: /*
002: * Copyright 2005-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.core.inquiry;
017:
018: import java.security.GeneralSecurityException;
019: import java.util.ArrayList;
020: import java.util.Collection;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.Properties;
026:
027: import org.apache.commons.lang.StringUtils;
028: import org.kuali.RiceConstants;
029: import org.kuali.core.bo.BusinessObject;
030: import org.kuali.core.bo.user.UniversalUser;
031: import org.kuali.core.datadictionary.InquirySectionDefinition;
032: import org.kuali.core.lookup.CollectionIncomplete;
033: import org.kuali.core.lookup.LookupUtils;
034: import org.kuali.core.service.BusinessObjectDictionaryService;
035: import org.kuali.core.service.DataDictionaryService;
036: import org.kuali.core.service.EncryptionService;
037: import org.kuali.core.service.LookupService;
038: import org.kuali.core.service.PersistenceStructureService;
039: import org.kuali.core.service.UniversalUserService;
040: import org.kuali.core.util.InactiveRecordsHidingUtils;
041: import org.kuali.core.util.ObjectUtils;
042: import org.kuali.core.util.UrlFactory;
043: import org.kuali.core.web.format.Formatter;
044: import org.kuali.core.web.ui.Section;
045: import org.kuali.core.web.ui.SectionBridge;
046: import org.kuali.rice.KNSServiceLocator;
047:
048: /**
049: * Kuali inquirable implementation. Implements methods necessary to retrieve the business object and render the ui.
050: *
051: * NOTE: this class is not thread safe. When using this class or any subclasses in Spring, make sure that this is not a singleton service, or
052: * serious errors may occur.
053: */
054: public class KualiInquirableImpl implements Inquirable {
055: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
056: .getLogger(KualiInquirableImpl.class);
057:
058: private BusinessObjectDictionaryService dataDictionary;
059: private LookupService lookupService;
060: private Class businessObjectClass;
061:
062: private Map<String, Boolean> inactiveRecordDisplay;
063:
064: public static List<Class> HACK_LIST = new ArrayList<Class>();
065:
066: /**
067: * Default constructor, initializes services from spring
068: */
069: public KualiInquirableImpl() {
070: lookupService = KNSServiceLocator.getLookupService();
071: dataDictionary = KNSServiceLocator
072: .getBusinessObjectDictionaryService();
073: inactiveRecordDisplay = new HashMap<String, Boolean>();
074: }
075:
076: /**
077: * Return a business object by searching with map, the map keys should be a property name of the business object, with the map
078: * value as the value to search for.
079: */
080: public BusinessObject getBusinessObject(Map fieldValues) {
081: if (getBusinessObjectClass() == null) {
082: LOG.error("Business object class not set in inquirable.");
083: throw new RuntimeException(
084: "Business object class not set in inquirable.");
085: }
086:
087: CollectionIncomplete searchResults = null;
088: // user inquiries need to go through user service
089: if (UniversalUser.class.equals(getBusinessObjectClass())) {
090: searchResults = (CollectionIncomplete) getUniversalUserService()
091: .findUniversalUsers(fieldValues);
092: } else {
093: searchResults = (CollectionIncomplete) lookupService
094: .findCollectionBySearch(getBusinessObjectClass(),
095: fieldValues);
096: }
097:
098: BusinessObject foundObject = null;
099: if (searchResults != null && searchResults.size() > 0) {
100: foundObject = (BusinessObject) searchResults.get(0);
101: }
102: return foundObject;
103: }
104:
105: /**
106: * Objects extending KualiInquirableBase must specify the Section objects used to display the inquiry result.
107: */
108: public List<Section> getSections(BusinessObject bo) {
109:
110: List<Section> sections = new ArrayList<Section>();
111: if (getBusinessObjectClass() == null) {
112: LOG.error("Business object class not set in inquirable.");
113: throw new RuntimeException(
114: "Business object class not set in inquirable.");
115: }
116:
117: Collection inquirySections = dataDictionary
118: .getInquirySections(getBusinessObjectClass());
119: for (Iterator iter = inquirySections.iterator(); iter.hasNext();) {
120:
121: InquirySectionDefinition inquirySection = (InquirySectionDefinition) iter
122: .next();
123: Section section = SectionBridge.toSection(this ,
124: inquirySection, bo);
125: sections.add(section);
126:
127: }
128:
129: return sections;
130: }
131:
132: /**
133: * Helper method to build an inquiry url for a result field.
134: *
135: * @param bo the business object instance to build the urls for
136: * @param propertyName the property which links to an inquirable
137: * @return String url to inquiry
138: */
139: public String getInquiryUrl(BusinessObject businessObject,
140: String attributeName, boolean forceInquiry) {
141: Properties parameters = new Properties();
142: parameters.put(RiceConstants.DISPATCH_REQUEST_PARAMETER,
143: "start");
144:
145: BusinessObjectDictionaryService businessDictionary = KNSServiceLocator
146: .getBusinessObjectDictionaryService();
147: PersistenceStructureService persistenceStructureService = KNSServiceLocator
148: .getPersistenceStructureService();
149: DataDictionaryService dataDictionaryService = KNSServiceLocator
150: .getDataDictionaryService();
151: EncryptionService encryptionService = KNSServiceLocator
152: .getEncryptionService();
153:
154: Class inquiryBusinessObjectClass = null;
155: String attributeRefName = "";
156: boolean isPkReference = false;
157: if (attributeName.equals(businessDictionary
158: .getTitleAttribute(businessObject.getClass()))) {
159: inquiryBusinessObjectClass = businessObject.getClass();
160: isPkReference = true;
161: } else {
162: if (ObjectUtils.isNestedAttribute(attributeName)) {
163: inquiryBusinessObjectClass = LookupUtils
164: .getNestedReferenceClass(businessObject,
165: attributeName);
166: } else {
167: Map primitiveReference = LookupUtils
168: .getPrimitiveReference(businessObject,
169: attributeName);
170: if (primitiveReference != null
171: && !primitiveReference.isEmpty()) {
172: attributeRefName = (String) primitiveReference
173: .keySet().iterator().next();
174: inquiryBusinessObjectClass = (Class) primitiveReference
175: .get(attributeRefName);
176: }
177: }
178: }
179:
180: if (inquiryBusinessObjectClass == null
181: || businessDictionary
182: .isInquirable(inquiryBusinessObjectClass) == null
183: || !businessDictionary.isInquirable(
184: inquiryBusinessObjectClass).booleanValue()) {
185: return RiceConstants.EMPTY_STRING;
186: }
187:
188: synchronized (HACK_LIST) {
189: for (Class clazz : HACK_LIST) {
190: if (clazz.isAssignableFrom(inquiryBusinessObjectClass)) {
191: inquiryBusinessObjectClass = clazz;
192: break;
193: }
194: }
195: }
196:
197: parameters.put(RiceConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE,
198: inquiryBusinessObjectClass.getName());
199:
200: List keys = new ArrayList();
201: if (persistenceStructureService
202: .isPersistable(inquiryBusinessObjectClass)) {
203: keys = persistenceStructureService
204: .listPrimaryKeyFieldNames(inquiryBusinessObjectClass);
205: }
206:
207: // build key value url parameters used to retrieve the business object
208: String keyName = null;
209: String keyConversion = null;
210: String encryptedList = "";
211: for (Iterator iter = keys.iterator(); iter.hasNext();) {
212: keyName = (String) iter.next();
213: keyConversion = keyName;
214: if (ObjectUtils.isNestedAttribute(attributeName)) {
215: keyConversion = ObjectUtils
216: .getNestedAttributePrefix(attributeName)
217: + "." + keyName;
218: } else {
219: if (isPkReference) {
220: keyConversion = keyName;
221: } else {
222: keyConversion = persistenceStructureService
223: .getForeignKeyFieldName(businessObject
224: .getClass(), attributeRefName,
225: keyName);
226: }
227: }
228: Object keyValue = null;
229: if (keyConversion != null) {
230: keyValue = ObjectUtils.getPropertyValue(businessObject,
231: keyConversion);
232: }
233:
234: if (keyValue == null) {
235: keyValue = "";
236: } else if (keyValue instanceof java.sql.Date) { //format the date for passing in url
237: if (Formatter.findFormatter(keyValue.getClass()) != null) {
238: Formatter formatter = Formatter
239: .getFormatter(keyValue.getClass());
240: keyValue = (String) formatter.format(keyValue);
241: }
242: } else {
243: keyValue = keyValue.toString();
244: }
245:
246: // Encrypt value if it is a secure field
247: String displayWorkgroup = dataDictionaryService
248: .getAttributeDisplayWorkgroup(businessObject
249: .getClass(), keyName);
250: if (StringUtils.isNotBlank(displayWorkgroup)) {
251: try {
252: keyValue = encryptionService.encrypt(keyValue);
253: } catch (GeneralSecurityException e) {
254: LOG
255: .error(
256: "Exception while trying to encrypted value for inquiry framework.",
257: e);
258: throw new RuntimeException(e);
259: }
260:
261: // add to parameter list so that KualiInquiryAction can identify which parameters are encrypted
262: if (encryptedList.equals("")) {
263: encryptedList = keyName;
264: } else {
265: encryptedList = encryptedList
266: + RiceConstants.FIELD_CONVERSIONS_SEPERATOR
267: + keyName;
268: }
269: }
270:
271: parameters.put(keyName, keyValue);
272: }
273:
274: // if we did encrypt a value (or values), add the list of those that are encrypted to the parameters
275: if (!encryptedList.equals("")) {
276: parameters.put(RiceConstants.ENCRYPTED_LIST_PREFIX,
277: encryptedList);
278: }
279:
280: return UrlFactory.parameterizeUrl(RiceConstants.INQUIRY_ACTION,
281: parameters);
282: }
283:
284: public void addAdditionalSections(List columns, BusinessObject bo) {
285: }
286:
287: /**
288: * @see org.kuali.core.inquiry.Inquirable#getHtmlMenuBar()
289: */
290: public String getHtmlMenuBar() {
291: // TODO: replace with inquiry menu bar
292: return dataDictionary
293: .getLookupMenuBar(getBusinessObjectClass());
294: }
295:
296: /**
297: * @see org.kuali.core.inquiry.Inquirable#getTitle()
298: */
299: public String getTitle() {
300: return dataDictionary.getInquiryTitle(getBusinessObjectClass());
301: }
302:
303: /**
304: * @return Returns the businessObjectClass.
305: */
306: public Class getBusinessObjectClass() {
307: return businessObjectClass;
308: }
309:
310: /**
311: * @param businessObjectClass The businessObjectClass to set.
312: */
313: public void setBusinessObjectClass(Class businessObjectClass) {
314: this .businessObjectClass = businessObjectClass;
315: }
316:
317: /**
318: * Gets the kualiUserService attribute.
319: *
320: * @return Returns the kualiUserService.
321: */
322: public UniversalUserService getUniversalUserService() {
323: return KNSServiceLocator.getUniversalUserService();
324: }
325:
326: /**
327: * @see org.kuali.core.inquiry.Inquirable#getInactiveRecordDisplay()
328: */
329: public Map<String, Boolean> getInactiveRecordDisplay() {
330: return inactiveRecordDisplay;
331: }
332:
333: /**
334: * @see org.kuali.core.inquiry.Inquirable#getShowInactiveRecords(java.lang.String)
335: */
336: public boolean getShowInactiveRecords(String collectionName) {
337: return InactiveRecordsHidingUtils.getShowInactiveRecords(
338: inactiveRecordDisplay, collectionName);
339: }
340:
341: /**
342: * @see org.kuali.core.inquiry.Inquirable#setShowInactiveRecords(java.lang.String, boolean)
343: */
344: public void setShowInactiveRecords(String collectionName,
345: boolean showInactive) {
346: InactiveRecordsHidingUtils.setShowInactiveRecords(
347: inactiveRecordDisplay, collectionName, showInactive);
348: }
349: }
|