001package org.kuali.rice.krad.dao.impl; 002 003import org.apache.commons.lang.StringUtils; 004import org.apache.ojb.broker.query.Criteria; 005import org.apache.ojb.broker.query.QueryByCriteria; 006import org.apache.ojb.broker.query.QueryFactory; 007import org.kuali.rice.core.framework.persistence.ojb.dao.PlatformAwareDaoBaseOjb; 008import org.kuali.rice.kns.service.KNSServiceLocator; 009import org.kuali.rice.krad.bo.BusinessObject; 010import org.kuali.rice.krad.bo.PersistableBusinessObject; 011import org.kuali.rice.krad.dao.BusinessObjectDao; 012import org.kuali.rice.krad.service.PersistenceStructureService; 013import org.kuali.rice.krad.service.util.OjbCollectionAware; 014import org.kuali.rice.krad.service.util.OjbCollectionHelper; 015import org.kuali.rice.krad.util.KRADPropertyConstants; 016import org.kuali.rice.krad.util.ObjectUtils; 017import org.springframework.dao.DataAccessException; 018import org.springframework.orm.ObjectRetrievalFailureException; 019 020import java.lang.reflect.InvocationTargetException; 021import java.util.*; 022 023/** 024 * Created by angelind on 11/6/14. 025 * 026 * Overridden by 'Sheik Salahudeen' 027 * Overridden for fixing the document fetching issue in KRAD Transaction document with OJB. 028 * Modified method names: findBySinglePrimaryKey,findByPrimaryKey,findAll,findAllOrderBy,findMatching,findAllActive,findAllInactive,findAllActiveOrderBy,findMatchingActive,findMatchingOrderBy,findByPrimaryKeyUsingKeyObject,buildCriteria 029 * Changes description : Modified the return type of method from '<T extends BusinessObject>' to '<T>'. 030 */ 031@Deprecated 032public class BusinessObjectDaoOjb extends PlatformAwareDaoBaseOjb implements BusinessObjectDao, OjbCollectionAware { 033 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BusinessObjectDaoOjb.class); 034 035 private PersistenceStructureService persistenceStructureService; 036 private OjbCollectionHelper ojbCollectionHelper; 037 038 /** 039 * This constructs a {@link BusinessObjectDaoOjb} 040 */ 041 public BusinessObjectDaoOjb(PersistenceStructureService persistenceStructureService) { 042 this.persistenceStructureService = persistenceStructureService; 043 } 044 045 /** 046 * @see org.kuali.rice.krad.dao.BusinessObjectDao#findBySinglePrimaryKey(java.lang.Class, java.lang.Object) 047 */ 048 public <T> T findBySinglePrimaryKey(Class<T> clazz, Object primaryKey) { 049 if (primaryKey.getClass().getName().startsWith("java.lang.") 050 || primaryKey.getClass().getName().startsWith("java.sql.") 051 || primaryKey.getClass().getName().startsWith("java.math.") 052 || primaryKey.getClass().getName().startsWith("java.util.")) { 053 try { 054 return (T) getPersistenceBrokerTemplate().getObjectById(clazz, primaryKey); 055 } catch ( ObjectRetrievalFailureException ex ) { 056 // it doesn't exist, just return null 057 return null; 058 } 059 } else { 060 Criteria criteria = buildCriteria(clazz, primaryKey); 061 062 return (T) getPersistenceBrokerTemplate().getObjectByQuery(QueryFactory.newQuery(clazz, criteria)); 063 } 064 } 065 066 /** 067 * @see org.kuali.rice.krad.dao.BusinessObjectDao#findByPrimaryKey(java.lang.Class, java.util.Map) 068 */ 069 public <T> T findByPrimaryKey(Class<T> clazz, Map<String, ?> primaryKeys) { 070 Criteria criteria = buildCriteria(primaryKeys); 071 072 return (T) getPersistenceBrokerTemplate().getObjectByQuery(QueryFactory.newQuery(clazz, criteria)); 073 } 074 075 /** 076 * Retrieves all of the records for a given class name. 077 * 078 * @param clazz - the name of the object being used, either KualiCodeBase or a subclass 079 * @return Collection 080 * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAll(java.lang.Class) 081 */ 082 public <T> Collection<T> findAll(Class<T> clazz) { 083 return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(clazz, (Criteria) null)); 084 } 085 086 /** 087 * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAllOrderBy(java.lang.Class, java.lang.String, boolean) 088 */ 089 public <T> Collection<T> findAllOrderBy(Class<T> clazz, String sortField, boolean sortAscending) { 090 QueryByCriteria queryByCriteria = new QueryByCriteria(clazz, (Criteria) null); 091 092 if (sortAscending) { 093 queryByCriteria.addOrderByAscending(sortField); 094 } 095 else { 096 queryByCriteria.addOrderByDescending(sortField); 097 } 098 099 return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(queryByCriteria); 100 } 101 102 /** 103 * This is the default impl that comes with Kuali - uses OJB. 104 * 105 * @see org.kuali.rice.krad.dao.BusinessObjectDao#findMatching(java.lang.Class, java.util.Map) 106 */ 107 public <T> Collection<T> findMatching(Class<T> clazz, Map<String, ?> fieldValues) { 108 Criteria criteria = buildCriteria(fieldValues); 109 110 return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(clazz, criteria)); 111 } 112 113 /** 114 * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAllActive(java.lang.Class) 115 */ 116 public <T> Collection<T> findAllActive(Class<T> clazz) { 117 return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(clazz, buildActiveCriteria())); 118 } 119 120 /** 121 * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAllActive(java.lang.Class) 122 */ 123 public <T> Collection<T> findAllInactive(Class<T> clazz) { 124 return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(clazz, buildInactiveCriteria())); 125 } 126 127 /** 128 * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAllActiveOrderBy(java.lang.Class, java.lang.String, boolean) 129 */ 130 public <T> Collection<T> findAllActiveOrderBy(Class<T> clazz, String sortField, boolean sortAscending) { 131 QueryByCriteria queryByCriteria = new QueryByCriteria(clazz, buildActiveCriteria()); 132 133 if (sortAscending) { 134 queryByCriteria.addOrderByAscending(sortField); 135 } 136 else { 137 queryByCriteria.addOrderByDescending(sortField); 138 } 139 140 return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(queryByCriteria); 141 } 142 143 /** 144 * @see org.kuali.rice.krad.dao.BusinessObjectDao#findMatchingActive(java.lang.Class, java.util.Map) 145 */ 146 public <T> Collection<T> findMatchingActive(Class<T> clazz, Map<String, ?> fieldValues) { 147 Criteria criteria = buildCriteria(fieldValues); 148 criteria.addAndCriteria(buildActiveCriteria()); 149 150 return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(clazz, criteria)); 151 } 152 153 /** 154 * This is the default impl that comes with Kuali - uses OJB. 155 * 156 * @see org.kuali.rice.krad.dao.BusinessObjectDao#countMatching(java.lang.Class, java.util.Map) 157 */ 158 public int countMatching(Class clazz, Map<String, ?> fieldValues) { 159 Criteria criteria = buildCriteria(fieldValues); 160 161 return getPersistenceBrokerTemplate().getCount(QueryFactory.newQuery(clazz, criteria)); 162 } 163 164 /** 165 * This is the default impl that comes with Kuali - uses OJB. 166 * 167 * @see org.kuali.rice.krad.dao.BusinessObjectDao#countMatching(java.lang.Class, java.util.Map, java.util.Map) 168 */ 169 public int countMatching(Class clazz, Map<String, ?> positiveFieldValues, Map<String, ?> negativeFieldValues) { 170 Criteria criteria = buildCriteria(positiveFieldValues); 171 Criteria negativeCriteria = buildNegativeCriteria(negativeFieldValues); 172 criteria.addAndCriteria(negativeCriteria); 173 return getPersistenceBrokerTemplate().getCount(QueryFactory.newQuery(clazz, criteria)); 174 } 175 176 177 /** 178 * This is the default impl that comes with Kuali - uses OJB. 179 * 180 * @see org.kuali.rice.krad.dao.BusinessObjectDao#findMatching(java.lang.Class, java.util.Map) 181 */ 182 public <T> Collection<T> findMatchingOrderBy(Class<T> clazz, Map<String, ?> fieldValues, String sortField, boolean sortAscending) { 183 Criteria criteria = buildCriteria(fieldValues); 184 QueryByCriteria queryByCriteria = new QueryByCriteria(clazz, criteria); 185 186 if (sortAscending) { 187 queryByCriteria.addOrderByAscending(sortField); 188 } 189 else { 190 queryByCriteria.addOrderByDescending(sortField); 191 } 192 193 return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(queryByCriteria); 194 } 195 196 /** 197 * Saves a business object. 198 * 199 * @see org.kuali.rice.krad.dao.BusinessObjectDao#save(org.kuali.rice.krad.bo.PersistableBusinessObject) 200 */ 201 public PersistableBusinessObject save(PersistableBusinessObject bo) throws DataAccessException { 202 // if collections exist on the BO, create a copy and use to process the 203 // collections to ensure 204 // that removed elements are deleted from the database 205 Set<String> boCollections = getPersistenceStructureService().listCollectionObjectTypes(bo.getClass()).keySet(); 206 PersistableBusinessObject savedBo = null; 207 if (!boCollections.isEmpty()) { 208 // refresh bo to get db copy of collections 209 savedBo = (PersistableBusinessObject) ObjectUtils.deepCopy(bo); 210 for (String boCollection : boCollections) { 211 if (getPersistenceStructureService().isCollectionUpdatable(savedBo.getClass(), boCollection)) { 212 savedBo.refreshReferenceObject(boCollection); 213 } 214 } 215 getOjbCollectionHelper().processCollections(this, bo, savedBo); 216 } 217 218 getPersistenceBrokerTemplate().store(bo); 219 return bo; 220 } 221 222 /** 223 * Saves a business object. 224 * 225 * @see org.kuali.rice.krad.dao.BusinessObjectDao#save(org.kuali.rice.krad.bo.PersistableBusinessObject) 226 */ 227 public List<? extends PersistableBusinessObject> save(List businessObjects) throws DataAccessException { 228 if ( LOG.isDebugEnabled() ) { 229 LOG.debug( "About to persist the following BOs:" ); 230 for ( Object bo : businessObjects ) { 231 LOG.debug( " --->" + bo ); 232 } 233 } 234 for (Iterator i = businessObjects.iterator(); i.hasNext();) { 235 Object bo = i.next(); 236 getPersistenceBrokerTemplate().store(bo); 237 } 238 return businessObjects; 239 } 240 241 242 /** 243 * Deletes the business object passed in. 244 * 245 * @param bo 246 * @throws DataAccessException 247 * @see org.kuali.rice.krad.dao.BusinessObjectDao#delete(org.kuali.rice.krad.bo.PersistableBusinessObject) 248 */ 249 public void delete(Object bo) { 250 getPersistenceBrokerTemplate().delete(bo); 251 } 252 253 /** 254 * @see org.kuali.rice.krad.dao.BusinessObjectDao#delete(java.util.List) 255 */ 256 public void delete(List<? extends PersistableBusinessObject> boList) { 257 for (PersistableBusinessObject bo : boList) { 258 getPersistenceBrokerTemplate().delete(bo); 259 } 260 } 261 262 263 /** 264 * @see org.kuali.rice.krad.dao.BusinessObjectDao#deleteMatching(java.lang.Class, java.util.Map) 265 */ 266 public void deleteMatching(Class clazz, Map<String, ?> fieldValues) { 267 Criteria criteria = buildCriteria(fieldValues); 268 269 getPersistenceBrokerTemplate().deleteByQuery(QueryFactory.newQuery(clazz, criteria)); 270 271 // An ojb delete by query doesn't update the cache so we need to clear the cache for everything to work property. 272 // don't believe me? Read the source code to OJB 273 getPersistenceBrokerTemplate().clearCache(); 274 } 275 276 /** 277 * @see org.kuali.rice.krad.dao.BusinessObjectDao#retrieve(org.kuali.rice.krad.bo.PersistableBusinessObject) 278 */ 279 public Object retrieve(Object object) { 280 return getPersistenceBrokerTemplate().getObjectByQuery(QueryFactory.newQueryByIdentity(object)); 281 } 282 283 /** 284 * OJB does not support this method 285 * @see org.kuali.rice.krad.dao.BusinessObjectDao#findByPrimaryKey(java.lang.Class, java.lang.Object) 286 */ 287 public <T> T findByPrimaryKeyUsingKeyObject(Class<T> clazz, Object pkObject) { 288 throw new UnsupportedOperationException("OJB does not support this option"); 289 } 290 291 /** 292 * No need to do anything - avoid saving and OJB will "manage read only" 293 * @see org.kuali.rice.krad.dao.BusinessObjectDao#manageReadOnly(org.kuali.rice.krad.bo.PersistableBusinessObject) 294 */ 295 public PersistableBusinessObject manageReadOnly(PersistableBusinessObject bo) { 296 return bo; 297 } 298 299 /** 300 * This method will build out criteria in the key-value paradigm (attribute-value). 301 * 302 * @param fieldValues 303 * @return 304 */ 305 private Criteria buildCriteria(Map<String, ?> fieldValues) { 306 Criteria criteria = new Criteria(); 307 for (Iterator i = fieldValues.entrySet().iterator(); i.hasNext();) { 308 Map.Entry<String, Object> e = (Map.Entry<String, Object>) i.next(); 309 310 String key = e.getKey(); 311 Object value = e.getValue(); 312 if (value instanceof Collection) { 313 criteria.addIn(key, (Collection) value); 314 } else { 315 criteria.addEqualTo(key, value); 316 } 317 } 318 319 return criteria; 320 } 321 322 323 private <T> Criteria buildCriteria(Class<T> clazz, Object primaryKey) { 324 Map<String, Object> fieldValues = new HashMap<String, Object>(); 325 List<String> fieldNames = getPersistenceStructureService().getPrimaryKeys(clazz); 326 327 //create map of values 328 for (String fieldName : fieldNames) { 329 Object fieldValue; 330 331 try { 332 fieldValue = primaryKey.getClass().getMethod("get" + StringUtils.capitalize(fieldName)).invoke(primaryKey); 333 fieldValues.put(fieldName, fieldValue); 334 } catch (IllegalArgumentException e) { 335 e.printStackTrace(); 336 } catch (IllegalAccessException e) { 337 e.printStackTrace(); 338 } catch (SecurityException e) { 339 e.printStackTrace(); 340 } catch (InvocationTargetException e) { 341 e.printStackTrace(); 342 } catch (NoSuchMethodException e) { 343 e.printStackTrace(); 344 } 345 } 346 return this.buildCriteria(fieldValues); 347 } 348 349 /** 350 * Builds a Criteria object for active field set to true 351 * @return Criteria 352 */ 353 private Criteria buildActiveCriteria(){ 354 Criteria criteria = new Criteria(); 355 criteria.addEqualTo(KRADPropertyConstants.ACTIVE, true); 356 357 return criteria; 358 } 359 360 /** 361 * Builds a Criteria object for active field set to true 362 * @return Criteria 363 */ 364 private Criteria buildInactiveCriteria(){ 365 Criteria criteria = new Criteria(); 366 criteria.addEqualTo(KRADPropertyConstants.ACTIVE, false); 367 368 return criteria; 369 } 370 371 /** 372 * This method will build out criteria in the key-value paradigm (attribute-value). 373 * 374 * @param negativeFieldValues 375 * @return 376 */ 377 private Criteria buildNegativeCriteria(Map<String, ?> negativeFieldValues) { 378 Criteria criteria = new Criteria(); 379 for (Iterator i = negativeFieldValues.entrySet().iterator(); i.hasNext();) { 380 Map.Entry<String, Object> e = (Map.Entry<String, Object>) i.next(); 381 382 String key = e.getKey(); 383 Object value = e.getValue(); 384 if (value instanceof Collection) { 385 criteria.addNotIn(key, (Collection) value); 386 } 387 else { 388 criteria.addNotEqualTo(key, value); 389 } 390 } 391 392 return criteria; 393 } 394 395 /** 396 * Gets the persistenceStructureService attribute. 397 * @return Returns the persistenceStructureService. 398 */ 399 protected PersistenceStructureService getPersistenceStructureService() { 400 return persistenceStructureService; 401 } 402 403 /** 404 * Sets the persistenceStructureService attribute value. 405 * @param persistenceStructureService The persistenceStructureService to set. 406 */ 407 public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) { 408 this.persistenceStructureService = persistenceStructureService; 409 } 410 411 /** 412 * OJB collection helper instance which processes collections before persisting 413 * 414 * @return OjbCollectionHelper 415 */ 416 protected OjbCollectionHelper getOjbCollectionHelper() { 417 if (ojbCollectionHelper == null) { 418 ojbCollectionHelper = KNSServiceLocator.getOjbCollectionHelper(); 419 } 420 421 return ojbCollectionHelper; 422 } 423 424 /** 425 * Setter for the OJB collection helper 426 * 427 * @param ojbCollectionHelper 428 */ 429 public void setOjbCollectionHelper(OjbCollectionHelper ojbCollectionHelper) { 430 this.ojbCollectionHelper = ojbCollectionHelper; 431 } 432}