View Javadoc

1   /*
2    * Copyright 2011 The Kuali Foundation.
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.select.lookup;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.ole.sys.context.SpringContext;
20  import org.kuali.ole.sys.service.NonTransactional;
21  import org.kuali.rice.core.api.config.property.ConfigurationService;
22  import org.kuali.rice.core.api.search.SearchOperator;
23  import org.kuali.rice.kns.service.DataDictionaryService;
24  import org.kuali.rice.kns.service.KNSServiceLocator;
25  import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
26  import org.kuali.rice.krad.bo.PersistableBusinessObject;
27  import org.kuali.rice.krad.dao.LookupDao;
28  import org.kuali.rice.krad.datadictionary.BusinessObjectEntry;
29  import org.kuali.rice.krad.datadictionary.DataDictionaryEntry;
30  import org.kuali.rice.krad.datadictionary.PrimitiveAttributeDefinition;
31  import org.kuali.rice.krad.datadictionary.RelationshipDefinition;
32  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
33  import org.kuali.rice.krad.service.LookupService;
34  import org.kuali.rice.krad.service.ModuleService;
35  import org.kuali.rice.krad.service.PersistenceStructureService;
36  
37  import java.lang.reflect.Method;
38  import java.util.*;
39  
40  @NonTransactional
41  public class DocLookupServiceImpl implements LookupService {
42      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocLookupServiceImpl.class);
43  
44      //TODO:This is just a draft version .The whole class needs to be rewritten once we have Document store
45      private IDocLookupSearch lookupDao;
46      private LookupDao lookupDaoOjb;
47      private ConfigurationService kualiConfigurationService;
48      private DataDictionaryService dataDictionaryService;
49      private PersistenceStructureService persistenceStructureService;
50  
51  
52      @Override
53      public Collection findCollectionBySearchUnbounded(Class example, Map formProps) {
54          return findCollectionBySearchHelper(example, formProps, true);
55      }
56  
57      /**
58       * Returns a collection of objects based on the given search parameters.
59       *
60       * @return Collection returned from the search
61       */
62  
63      @Override
64      public Collection findCollectionBySearch(Class example, Map formProps) {
65          try {
66              return getResult(example, formProps, true);
67          } catch (Exception e) {
68              throw new RuntimeException(e);
69          }
70      }
71  
72  
73      @Override
74      public Collection findCollectionBySearchHelper(Class example, Map formProps, boolean unbounded) {
75          try {
76              return getResult(example, formProps, true);
77          } catch (Exception e) {
78              throw new RuntimeException(e);
79          }
80      }
81  
82      /**
83       * Retrieves a Object based on the search criteria, which should uniquely identify a record.
84       *
85       * @return Object returned from the search
86       */
87  
88      @Override
89      public Object findObjectBySearch(Class example, Map formProps) {
90          if (example == null || formProps == null) {
91              throw new IllegalArgumentException("Object and Map must not be null");
92          }
93  
94          PersistableBusinessObject obj = null;
95          try {
96              obj = (PersistableBusinessObject) example.newInstance();
97          } catch (IllegalAccessException e) {
98              throw new RuntimeException("Cannot get new instance of " + example.getName(), e);
99          } 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 }
349