1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kns.lookup;
17
18 import org.apache.commons.beanutils.PropertyUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.kuali.rice.core.api.CoreApiServiceLocator;
21 import org.kuali.rice.core.api.encryption.EncryptionService;
22 import org.kuali.rice.core.api.search.SearchOperator;
23 import org.kuali.rice.krad.bo.BusinessObject;
24 import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
25 import org.kuali.rice.krad.datadictionary.BusinessObjectEntry;
26 import org.kuali.rice.krad.datadictionary.RelationshipDefinition;
27 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
28 import org.kuali.rice.krad.service.ModuleService;
29 import org.kuali.rice.krad.util.BeanPropertyComparator;
30 import org.kuali.rice.krad.util.ExternalizableBusinessObjectUtils;
31 import org.kuali.rice.krad.util.KRADConstants;
32 import org.kuali.rice.krad.util.ObjectUtils;
33 import org.springframework.transaction.annotation.Transactional;
34
35 import java.security.GeneralSecurityException;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Set;
44
45 @Transactional
46 public class KualiLookupableHelperServiceImpl extends AbstractLookupableHelperServiceImpl {
47
48 protected static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiLookupableHelperServiceImpl.class);
49 protected boolean searchUsingOnlyPrimaryKeyValues = false;
50
51
52
53
54
55
56
57
58
59
60 public List<? extends BusinessObject> getSearchResults(Map<String, String> fieldValues) {
61 return getSearchResultsHelper(
62 org.kuali.rice.krad.lookup.LookupUtils.forceUppercase(getBusinessObjectClass(), fieldValues), false);
63 }
64
65
66
67
68
69
70
71
72
73
74 public List<? extends BusinessObject> getSearchResultsUnbounded(Map<String, String> fieldValues) {
75 return getSearchResultsHelper(
76 org.kuali.rice.krad.lookup.LookupUtils.forceUppercase(getBusinessObjectClass(), fieldValues), true);
77 }
78
79
80
81
82
83
84
85
86 protected boolean isExternalBusinessObjectProperty(Object sampleBo, String propertyName) {
87 try {
88 if ( propertyName.indexOf( "." ) > 0 && !StringUtils.contains( propertyName, "add." ) ) {
89 Class propertyClass = PropertyUtils.getPropertyType(
90 sampleBo, StringUtils.substringBeforeLast( propertyName, "." ) );
91 if ( propertyClass != null ) {
92 return ExternalizableBusinessObjectUtils.isExternalizableBusinessObjectInterface( propertyClass );
93 } else {
94 if ( LOG.isDebugEnabled() ) {
95 LOG.debug( "unable to get class for " + StringUtils.substringBeforeLast( propertyName, "." ) + " on " + sampleBo.getClass().getName() );
96 }
97 }
98 }
99 } catch (Exception e) {
100 LOG.debug("Unable to determine type of property for " + sampleBo.getClass().getName() + "/" + propertyName, e );
101 }
102 return false;
103 }
104
105
106
107
108
109
110
111
112 protected String getExternalBusinessObjectProperty(Object sampleBo, String propertyName) {
113 if ( propertyName.indexOf( "." ) > 0 && !StringUtils.contains( propertyName, "add." ) ) {
114 return StringUtils.substringBeforeLast( propertyName, "." );
115 }
116 return null;
117 }
118
119
120
121
122 protected boolean hasExternalBusinessObjectProperty(Class boClass, Map<String,String> fieldValues ) {
123 try {
124 Object sampleBo = boClass.newInstance();
125 for ( String key : fieldValues.keySet() ) {
126 if ( isExternalBusinessObjectProperty( sampleBo, key )) {
127 return true;
128 }
129 }
130 } catch ( Exception ex ) {
131 LOG.debug("Unable to check " + boClass + " for EBO properties.", ex );
132 }
133 return false;
134 }
135
136
137
138
139
140 protected Map<String,String> removeExternalizableBusinessObjectFieldValues(Class boClass, Map<String,String> fieldValues ) {
141 Map<String,String> eboFieldValues = new HashMap<String,String>();
142 try {
143 Object sampleBo = boClass.newInstance();
144 for ( String key : fieldValues.keySet() ) {
145 if ( !isExternalBusinessObjectProperty( sampleBo, key )) {
146 eboFieldValues.put( key, fieldValues.get( key ) );
147 }
148 }
149 } catch ( Exception ex ) {
150 LOG.debug("Unable to check " + boClass + " for EBO properties.", ex );
151 }
152 return eboFieldValues;
153 }
154
155
156
157
158
159 protected Map<String,String> getExternalizableBusinessObjectFieldValues(String eboPropertyName, Map<String,String> fieldValues ) {
160 Map<String,String> eboFieldValues = new HashMap<String,String>();
161 for ( String key : fieldValues.keySet() ) {
162 if ( key.startsWith( eboPropertyName + "." ) ) {
163 eboFieldValues.put( StringUtils.substringAfterLast( key, "." ), fieldValues.get( key ) );
164 }
165 }
166 return eboFieldValues;
167 }
168
169
170
171
172
173
174 protected List<String> getExternalizableBusinessObjectProperties(Class boClass, Map<String,String> fieldValues ) {
175 Set<String> eboPropertyNames = new HashSet<String>();
176 try {
177 Object sampleBo = boClass.newInstance();
178 for ( String key : fieldValues.keySet() ) {
179 if ( isExternalBusinessObjectProperty( sampleBo, key )) {
180 eboPropertyNames.add( StringUtils.substringBeforeLast( key, "." ) );
181 }
182 }
183 } catch ( Exception ex ) {
184 LOG.debug("Unable to check " + boClass + " for EBO properties.", ex );
185 }
186 return new ArrayList<String>(eboPropertyNames);
187 }
188
189
190
191
192
193
194
195
196
197 protected Class<? extends ExternalizableBusinessObject> getExternalizableBusinessObjectClass(Class boClass, String propertyName) {
198 try {
199 return PropertyUtils.getPropertyType(
200 boClass.newInstance(), StringUtils.substringBeforeLast( propertyName, "." ) );
201 } catch (Exception e) {
202 LOG.debug("Unable to determine type of property for " + boClass.getName() + "/" + propertyName, e );
203 }
204 return null;
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218
219 protected List<? extends BusinessObject> getSearchResultsHelper(Map<String, String> fieldValues, boolean unbounded) {
220
221 LookupUtils.removeHiddenCriteriaFields(getBusinessObjectClass(), fieldValues);
222
223 searchUsingOnlyPrimaryKeyValues = getLookupService().allPrimaryKeyValuesPresentAndNotWildcard(getBusinessObjectClass(), fieldValues);
224
225 setBackLocation(fieldValues.get(KRADConstants.BACK_LOCATION));
226 setDocFormKey(fieldValues.get(KRADConstants.DOC_FORM_KEY));
227 setReferencesToRefresh(fieldValues.get(KRADConstants.REFERENCES_TO_REFRESH));
228 List searchResults;
229 Map<String,String> nonBlankFieldValues = new HashMap<String, String>();
230 for (String fieldName : fieldValues.keySet()) {
231 String fieldValue = fieldValues.get(fieldName);
232 if (StringUtils.isNotBlank(fieldValue) ) {
233 if (fieldValue.endsWith(EncryptionService.ENCRYPTION_POST_PREFIX)) {
234 String encryptedValue = StringUtils.removeEnd(fieldValue, EncryptionService.ENCRYPTION_POST_PREFIX);
235 try {
236 if(CoreApiServiceLocator.getEncryptionService().isEnabled()) {
237 fieldValue = getEncryptionService().decrypt(encryptedValue);
238 }
239 }
240 catch (GeneralSecurityException e) {
241 LOG.error("Error decrypting value for business object " + getBusinessObjectService() + " attribute " + fieldName, e);
242 throw new RuntimeException("Error decrypting value for business object " + getBusinessObjectService() + " attribute " + fieldName, e);
243 }
244 }
245 nonBlankFieldValues.put(fieldName, fieldValue);
246 }
247 }
248
249
250 if ( ExternalizableBusinessObjectUtils.isExternalizableBusinessObject( getBusinessObjectClass() ) ) {
251 ModuleService eboModuleService = KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService( getBusinessObjectClass() );
252 BusinessObjectEntry ddEntry = eboModuleService.getExternalizableBusinessObjectDictionaryEntry(getBusinessObjectClass());
253 Map<String,String> filteredFieldValues = new HashMap<String, String>();
254 for (String fieldName : nonBlankFieldValues.keySet()) {
255 if (ddEntry.getAttributeNames().contains(fieldName)) {
256 filteredFieldValues.put(fieldName, nonBlankFieldValues.get(fieldName));
257 }
258 }
259 searchResults = eboModuleService.getExternalizableBusinessObjectsListForLookup(getBusinessObjectClass(), (Map)filteredFieldValues, unbounded);
260
261 } else if ( hasExternalBusinessObjectProperty( getBusinessObjectClass(), nonBlankFieldValues ) ) {
262 if ( LOG.isDebugEnabled() ) {
263 LOG.debug( "has EBO reference: " + getBusinessObjectClass() );
264 LOG.debug( "properties: " + nonBlankFieldValues );
265 }
266
267 Map<String,String> nonEboFieldValues = removeExternalizableBusinessObjectFieldValues( getBusinessObjectClass(), nonBlankFieldValues );
268 if ( LOG.isDebugEnabled() ) {
269 LOG.debug( "Non EBO properties removed: " + nonEboFieldValues );
270 }
271
272 List<String> eboPropertyNames = getExternalizableBusinessObjectProperties( getBusinessObjectClass(), nonBlankFieldValues );
273 if ( LOG.isDebugEnabled() ) {
274 LOG.debug( "EBO properties: " + eboPropertyNames );
275 }
276
277 for ( String eboPropertyName : eboPropertyNames ) {
278
279 Map<String,String> eboFieldValues = getExternalizableBusinessObjectFieldValues( eboPropertyName, nonBlankFieldValues );
280 if ( LOG.isDebugEnabled() ) {
281 LOG.debug( "EBO properties for master EBO property: " + eboPropertyName );
282 LOG.debug( "properties: " + eboFieldValues );
283 }
284
285 ModuleService eboModuleService = KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService( getExternalizableBusinessObjectClass( getBusinessObjectClass(), eboPropertyName) );
286
287 List eboResults = Collections.emptyList();
288 if (eboModuleService != null)
289 {
290 eboResults = eboModuleService.getExternalizableBusinessObjectsListForLookup( getExternalizableBusinessObjectClass( getBusinessObjectClass(), eboPropertyName), (Map)eboFieldValues, unbounded);
291 }
292 else
293 {
294 LOG.debug( "EBO ModuleService is null: " + eboPropertyName );
295 }
296
297
298
299
300 Class eboParentClass;
301 String eboParentPropertyName;
302 if ( ObjectUtils.isNestedAttribute( eboPropertyName ) ) {
303 eboParentPropertyName = StringUtils.substringBeforeLast( eboPropertyName, "." );
304 try {
305 eboParentClass = PropertyUtils.getPropertyType( getBusinessObjectClass().newInstance(), eboParentPropertyName );
306 } catch ( Exception ex ) {
307 throw new RuntimeException( "Unable to create an instance of the business object class: " + getBusinessObjectClass().getName(), ex );
308 }
309 } else {
310 eboParentClass = getBusinessObjectClass();
311 eboParentPropertyName = null;
312 }
313 if ( LOG.isDebugEnabled() ) {
314 LOG.debug( "determined EBO parent class/property name: " + eboParentClass + "/" + eboParentPropertyName );
315 }
316
317
318
319 RelationshipDefinition rd = getBusinessObjectMetaDataService().getBusinessObjectRelationshipDefinition( eboParentClass, eboPropertyName );
320 if ( LOG.isDebugEnabled() ) {
321 LOG.debug( "Obtained RelationshipDefinition for " + eboPropertyName );
322 LOG.debug( rd );
323 }
324
325
326
327
328
329 if ( ObjectUtils.isNotNull(rd)) {
330 if ( rd.getPrimitiveAttributes().size() > 1 ) {
331 throw new RuntimeException( "EBO Links don't work for relationships with multiple-field primary keys." );
332 }
333 String boProperty = rd.getPrimitiveAttributes().get( 0 ).getSourceName();
334 String eboProperty = rd.getPrimitiveAttributes().get( 0 ).getTargetName();
335 StringBuffer boPropertyValue = new StringBuffer();
336
337
338 for ( Object ebo : eboResults ) {
339 if ( boPropertyValue.length() != 0 ) {
340 boPropertyValue.append( SearchOperator.OR.op() );
341 }
342 try {
343 boPropertyValue.append( PropertyUtils.getProperty( ebo, eboProperty ).toString() );
344 } catch ( Exception ex ) {
345 LOG.warn( "Unable to get value for " + eboProperty + " on " + ebo );
346 }
347 }
348 if ( eboParentPropertyName == null ) {
349
350 nonEboFieldValues.put( boProperty, boPropertyValue.toString() );
351 } else {
352
353 nonEboFieldValues.put( eboParentPropertyName + "." + boProperty, boPropertyValue.toString() );
354 }
355 }
356 }
357 if ( LOG.isDebugEnabled() ) {
358 LOG.debug( "Passing these results into the lookup service: " + nonEboFieldValues );
359 }
360
361
362 searchResults = (List) getLookupService().findCollectionBySearchHelper(getBusinessObjectClass(), nonEboFieldValues, unbounded);
363 } else {
364 searchResults = (List) getLookupService().findCollectionBySearchHelper(getBusinessObjectClass(), nonBlankFieldValues, unbounded);
365 }
366
367 if (searchResults == null) {
368 searchResults = new ArrayList();
369 }
370
371
372 List defaultSortColumns = getDefaultSortColumns();
373 if (defaultSortColumns.size() > 0) {
374 Collections.sort(searchResults, new BeanPropertyComparator(defaultSortColumns, true));
375 }
376 return searchResults;
377 }
378
379
380
381
382
383 @Override
384 public boolean isSearchUsingOnlyPrimaryKeyValues() {
385 return searchUsingOnlyPrimaryKeyValues;
386 }
387
388
389
390
391
392
393
394
395
396
397
398 @Override
399 public String getPrimaryKeyFieldLabels() {
400 StringBuilder buf = new StringBuilder();
401 List<String> primaryKeyFieldNames = getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(getBusinessObjectClass());
402 Iterator<String> pkIter = primaryKeyFieldNames.iterator();
403 while (pkIter.hasNext()) {
404 String pkFieldName = (String) pkIter.next();
405 buf.append(getDataDictionaryService().getAttributeLabel(getBusinessObjectClass(), pkFieldName));
406 if (pkIter.hasNext()) {
407 buf.append(", ");
408 }
409 }
410 return buf.length() == 0 ? KRADConstants.NOT_AVAILABLE_STRING : buf.toString();
411 }
412
413
414 }
415