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