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