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