001/* 002 * Copyright 2011 The Kuali Foundation. 003 * 004 * Licensed under the Educational Community License, Version 2.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/ecl2.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 */ 016package org.kuali.ole.select.lookup; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.ole.sys.context.SpringContext; 020import org.kuali.ole.sys.service.NonTransactional; 021import org.kuali.rice.core.api.config.property.ConfigurationService; 022import org.kuali.rice.core.api.search.SearchOperator; 023import org.kuali.rice.kns.service.DataDictionaryService; 024import org.kuali.rice.kns.service.KNSServiceLocator; 025import org.kuali.rice.krad.bo.ExternalizableBusinessObject; 026import org.kuali.rice.krad.bo.PersistableBusinessObject; 027import org.kuali.rice.krad.dao.LookupDao; 028import org.kuali.rice.krad.datadictionary.BusinessObjectEntry; 029import org.kuali.rice.krad.datadictionary.DataDictionaryEntry; 030import org.kuali.rice.krad.datadictionary.PrimitiveAttributeDefinition; 031import org.kuali.rice.krad.datadictionary.RelationshipDefinition; 032import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 033import org.kuali.rice.krad.service.LookupService; 034import org.kuali.rice.krad.service.ModuleService; 035import org.kuali.rice.krad.service.PersistenceStructureService; 036 037import java.lang.reflect.Method; 038import java.util.*; 039 040@NonTransactional 041public class DocLookupServiceImpl implements LookupService { 042 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocLookupServiceImpl.class); 043 044 //TODO:This is just a draft version .The whole class needs to be rewritten once we have Document store 045 private IDocLookupSearch lookupDao; 046 private LookupDao lookupDaoOjb; 047 private ConfigurationService kualiConfigurationService; 048 private DataDictionaryService dataDictionaryService; 049 private PersistenceStructureService persistenceStructureService; 050 051 052 @Override 053 public Collection findCollectionBySearchUnbounded(Class example, Map formProps) { 054 return findCollectionBySearchHelper(example, formProps, true); 055 } 056 057 /** 058 * Returns a collection of objects based on the given search parameters. 059 * 060 * @return Collection returned from the search 061 */ 062 063 @Override 064 public Collection findCollectionBySearch(Class example, Map formProps) { 065 try { 066 return getResult(example, formProps, true); 067 } catch (Exception e) { 068 throw new RuntimeException(e); 069 } 070 } 071 072 073 @Override 074 public Collection findCollectionBySearchHelper(Class example, Map formProps, boolean unbounded) { 075 try { 076 return getResult(example, formProps, true); 077 } catch (Exception e) { 078 throw new RuntimeException(e); 079 } 080 } 081 082 /** 083 * Retrieves a Object based on the search criteria, which should uniquely identify a record. 084 * 085 * @return Object returned from the search 086 */ 087 088 @Override 089 public Object findObjectBySearch(Class example, Map formProps) { 090 if (example == null || formProps == null) { 091 throw new IllegalArgumentException("Object and Map must not be null"); 092 } 093 094 PersistableBusinessObject obj = null; 095 try { 096 obj = (PersistableBusinessObject) example.newInstance(); 097 } catch (IllegalAccessException e) { 098 throw new RuntimeException("Cannot get new instance of " + example.getName(), e); 099 } catch (InstantiationException e) { 100 throw new RuntimeException("Cannot instantiate " + example.getName(), e); 101 } 102 103 return lookupDaoOjb.findObjectByMap(obj, formProps); 104 } 105 106 107 @Override 108 public boolean allPrimaryKeyValuesPresentAndNotWildcard(Class boClass, Map formProps) { 109 List pkFields = KNSServiceLocator.getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(boClass); 110 Iterator pkIter = pkFields.iterator(); 111 boolean returnVal = true; 112 while (returnVal && pkIter.hasNext()) { 113 String pkName = (String) pkIter.next(); 114 String pkValue = (String) formProps.get(pkName); 115 116 if (StringUtils.isBlank(pkValue)) { 117 returnVal = false; 118 } else if (StringUtils.indexOfAny(pkValue, SearchOperator.QUERY_CHARACTERS.toArray().toString()) != -1) { 119 returnVal = false; 120 } 121 } 122 return returnVal; 123 } 124 125 /** 126 * @return Returns the lookupDao. 127 */ 128 129 public IDocLookupSearch getLookupDao() { 130 return lookupDao; 131 } 132 133 /** 134 * @param lookupDao The lookupDao to set. 135 */ 136 137 public void setLookupDao(IDocLookupSearch lookupDao) { 138 this.lookupDao = lookupDao; 139 } 140 141 142 public ConfigurationService getConfigurationService() { 143 return kualiConfigurationService; 144 } 145 146 147 public void setConfigurationService(ConfigurationService kualiConfigurationService) { 148 this.kualiConfigurationService = kualiConfigurationService; 149 } 150 151 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { 152 this.dataDictionaryService = dataDictionaryService; 153 } 154 155 /** 156 * @return Returns the lookupDao. 157 */ 158 159 public LookupDao getLookupDaoOjb() { 160 return lookupDaoOjb; 161 } 162 163 164 /** 165 * @param lookupDao The lookupDao to set. 166 */ 167 168 public void setLookupDaoOjb(LookupDao lookupDaoOjb) { 169 this.lookupDaoOjb = lookupDaoOjb; 170 } 171 172 173 public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) { 174 this.persistenceStructureService = persistenceStructureService; 175 } 176 177 178 private List getResult(Class businessObjectClass, Map criterValues, boolean unbounded) throws Exception { 179 List result = new ArrayList(); 180 Map dbCrit = new HashMap(); 181 Map docCrit = new HashMap(); 182 Map<String, List<String>> docData = getDDRelationship(businessObjectClass); 183 if (docData != null && docData.size() > 0) { 184 for (String key : (java.util.Set<String>) criterValues.keySet()) { 185 boolean found = false; 186 for (String key1 : docData.keySet()) { 187 { 188 if (key.contains(key1) && key.contains(".")) { 189 found = true; 190 String val = key.split("\\.")[key.split("\\.").length - 1]; 191 docCrit.put(val, criterValues.get(key));//dbCrit = null; 192 break; 193 } 194 } 195 if (!found) { 196 dbCrit.put(key, criterValues.get(key));//dbCrit = null; 197 } 198 } 199 } 200 } 201 if (ExternalizableBusinessObject.class.isAssignableFrom(businessObjectClass)) { 202 203 ModuleService eboModuleService = KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(businessObjectClass); 204 BusinessObjectEntry ddEntry = eboModuleService.getExternalizableBusinessObjectDictionaryEntry(businessObjectClass); 205 Map<String, String> filteredFieldValues = new HashMap<String, String>(); 206 for (String fieldName : (java.util.Set<String>) dbCrit.keySet()) { 207 if (ddEntry.getAttributeNames().contains(fieldName)) { 208 filteredFieldValues.put(fieldName, (String) dbCrit.get(fieldName)); 209 } 210 } 211 212 result = eboModuleService.getExternalizableBusinessObjectsListForLookup(businessObjectClass, 213 (Map) filteredFieldValues, unbounded); 214 215 } else if (!org.kuali.ole.select.lookup.DocStoreData.class.isAssignableFrom(businessObjectClass)) { 216 result = (List) this.getLookupDaoOjb().findCollectionBySearchHelper(businessObjectClass, dbCrit, unbounded, 217 allPrimaryKeyValuesPresentAndNotWildcard(businessObjectClass, dbCrit)); 218 } 219 Class cla = null; 220 for (String key : docData.keySet()) { 221 List<String> data = docData.get(key); 222 223 try { 224 cla = Class.forName(data.get(0)); 225 } catch (Exception e) { 226 throw new RuntimeException(e); 227 } 228 String attrs = data.get(1); 229 String[] ff = attrs.split(":")[0].split(","); 230 String sourAtt = null, targetAtt = null; 231 if (ff.length == 2) { 232 sourAtt = ff[0]; 233 targetAtt = ff[1]; 234 } 235 boolean isDBCrit = dbCrit == null || dbCrit.size() < 3; 236 boolean isDocCrit = docCrit == null || docCrit.size() < 1; 237 //retrieves the list of source/database attribute values 238 List dbSourceAttrib = getSourceData(result, sourAtt, businessObjectClass); 239 //retrieves the list of document store data for the corresponding source/database attribute values 240 List docStoreResult = this.getLookupDao().getResult(cla, targetAtt, dbSourceAttrib, docCrit);//docStoreResult.remove(2) 241 //merges both docstore and database data 242 result = mergeResult(result, sourAtt, businessObjectClass, docStoreResult, targetAtt, cla, docData.keySet().iterator().next(), isDBCrit, isDocCrit); 243 } 244 if (org.kuali.ole.select.lookup.DocStoreData.class.isAssignableFrom(businessObjectClass)) { 245 result = (List) this.getLookupDaoOjb().findCollectionBySearchHelper(businessObjectClass, criterValues, true, true); 246 } 247 return result; 248 } 249 250 private Method getMethod(Class c, String attr, Class[] objectAttributes) throws Exception { 251 Method met = c.getMethod("get" + StringUtils.capitalize(attr), objectAttributes); 252 return met; 253 } 254 255 private Method getSetMethod(Class c, String attr, Class[] objectAttributes) throws Exception { 256 attr = "docData"; 257 Method met = c.getMethod("set" + StringUtils.capitalize(attr), objectAttributes); 258 return met; 259 } 260 261 private List mergeResult(List result, String sourAtt, Class sourClass, List dres, String targetAtt, Class targeClass, 262 String attt, boolean isDBCrit, boolean isDocCrit) 263 throws Exception { 264 List resul = new ArrayList(); 265 List resut = new ArrayList(); 266 Class[] ptyeps = {targeClass}; 267 Method srcm = this.getMethod(sourClass, sourAtt, null); 268 Method tcm = this.getMethod(targeClass, targetAtt, null); 269 Method sem = this.getSetMethod(sourClass, attt, ptyeps); 270 for (Object val : result) { 271 for (Object dval : dres) { 272 Object sval = srcm.invoke(val, (Object[]) null); 273 Object dvall = tcm.invoke(dval, (Object[]) null); 274 if ((!isDocCrit && sval != null && sval.equals(dvall)) || (isDocCrit && dvall != null && dvall.equals(sval))) { 275 Object[] arr = {dval}; 276 sem.invoke(val, arr); 277 resul.add(val); 278 } 279 } 280 } 281 return resul; 282 283 } 284 285 private List<Object> getSourceData(List result, String objectAttribute, Class clas) throws Exception { 286 List<Object> resul = new ArrayList<Object>(0); 287 Method met = clas.getMethod("get" + StringUtils.capitalize(objectAttribute), (Class[]) null); 288 for (Object data : result) { 289 Object res = met.invoke(data, (Object[]) null); 290 if (res != null) { 291 resul.add(res); 292 } 293 } 294 return resul; 295 } 296 297 public Class getDocClass(Class clas, String objectAttribute) { 298 boolean result = false; 299 Method met = null; 300 try { 301 met = clas.getMethod("get" + StringUtils.capitalize(objectAttribute), (Class[]) null); 302 } catch (Exception e) { 303 return null; 304 } 305 return org.kuali.ole.select.lookup.DocStoreData.class.isAssignableFrom(met.getReturnType()) ? 306 met.getReturnType() : null; 307 } 308 309 310 public Map<String, List<String>> getDDRelationship(Class c) { 311 Map<String, List<String>> result = new HashMap<String, List<String>>(0); 312 DataDictionaryEntry entryBase = SpringContext.getBean(DataDictionaryService.class) 313 .getDataDictionary().getDictionaryObjectEntry(c.getName()); 314 if (entryBase == null) { 315 return null; 316 } 317 318 List<RelationshipDefinition> ddRelationships = entryBase 319 .getRelationships(); 320 RelationshipDefinition relationship = null; 321 int minKeys = Integer.MAX_VALUE; 322 for (RelationshipDefinition def : ddRelationships) { 323 // favor key sizes of 1 first 324 if (def.getPrimitiveAttributes().size() == 1) { 325 for (PrimitiveAttributeDefinition primitive : def 326 .getPrimitiveAttributes()) { 327 if (def.getObjectAttributeName() != null) { 328 List<String> data = new ArrayList<String>(0); 329 Class cc = getDocClass(c, def.getObjectAttributeName());//cc= null;data.remove("java.lang.String"); 330 if (cc != null) { 331 data.add(cc.getName()); 332 StringBuffer sb = new StringBuffer(); 333 List<PrimitiveAttributeDefinition> res = def.getPrimitiveAttributes(); 334 for (PrimitiveAttributeDefinition pdef : res) { 335 sb.append(pdef.getSourceName() + "," + pdef.getTargetName() + ":"); 336 } 337 sb.deleteCharAt(sb.length() - 1); 338 data.add(sb.toString()); 339 result.put(def.getObjectAttributeName(), data); 340 } 341 } 342 } 343 } 344 } 345 return result;//result.remove("oleRequestor"); 346 } 347 348 @Override 349 public <T> Collection<T> findCollectionBySearchHelper(Class<T> example, Map<String, String> formProperties, boolean unbounded, Integer searchResultsLimit) { 350 return null; //To change body of implemented methods use File | Settings | File Templates. 351 } 352} 353