1 /** 2 * Copyright 2005-2012 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.rice.krad.bo; 17 18 import org.apache.commons.lang.StringUtils; 19 import org.apache.ojb.broker.PersistenceBroker; 20 import org.apache.ojb.broker.PersistenceBrokerAware; 21 import org.apache.ojb.broker.PersistenceBrokerException; 22 import org.kuali.rice.core.api.mo.common.GloballyUnique; 23 import org.kuali.rice.core.api.mo.common.Versioned; 24 import org.kuali.rice.krad.service.KRADServiceLocator; 25 import org.kuali.rice.krad.service.PersistenceService; 26 import org.kuali.rice.krad.service.PersistenceStructureService; 27 28 import javax.persistence.Column; 29 import javax.persistence.MappedSuperclass; 30 import javax.persistence.PostLoad; 31 import javax.persistence.PostPersist; 32 import javax.persistence.PostRemove; 33 import javax.persistence.PostUpdate; 34 import javax.persistence.PrePersist; 35 import javax.persistence.PreRemove; 36 import javax.persistence.PreUpdate; 37 import javax.persistence.Transient; 38 import javax.persistence.Version; 39 import java.util.ArrayList; 40 import java.util.Collection; 41 import java.util.List; 42 import java.util.UUID; 43 44 /** 45 * @author Kuali Rice Team (rice.collab@kuali.org) 46 */ 47 @MappedSuperclass 48 public abstract class PersistableBusinessObjectBase extends BusinessObjectBase implements PersistableBusinessObject, PersistenceBrokerAware, Versioned, GloballyUnique { 49 private static final long serialVersionUID = 1451642350593233282L; 50 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PersistableBusinessObjectBase.class); 51 52 @Version 53 @Column(name="VER_NBR") 54 protected Long versionNumber; 55 @Column(name="OBJ_ID") 56 private String objectId; 57 @Transient 58 private boolean newCollectionRecord; 59 @Transient 60 protected PersistableBusinessObjectExtension extension; 61 62 private static transient PersistenceService persistenceService; 63 private static transient PersistenceStructureService persistenceStructureService; 64 65 /** 66 * @see PersistableBusinessObject#getVersionNumber() 67 */ 68 public Long getVersionNumber() { 69 return versionNumber; 70 } 71 72 /** 73 * @see PersistableBusinessObject#getVersionNumber() 74 */ 75 public void setVersionNumber(Long versionNumber) { 76 this.versionNumber = versionNumber; 77 } 78 79 80 /** 81 * getter for the guid based object id that is assignable to all objects, in order to support custom attributes a mapping must 82 * also be added to the OJB file and a column must be added to the database for each business object that extension attributes 83 * are supposed to work on. 84 * 85 * @return 86 */ 87 public String getObjectId() { 88 return objectId; 89 } 90 91 /** 92 * setter for the guid based object id that is assignable to all objects, in order to support custom attributes a mapping must 93 * also be added to the OJB file and column must be added to the database for each business object that extension attributes are 94 * supposed to work on. 95 * 96 * @param objectId 97 */ 98 public void setObjectId(String objectId) { 99 this.objectId = objectId; 100 } 101 102 103 /** 104 * Gets the newCollectionRecord attribute. 105 * 106 * @return Returns the newCollectionRecord. 107 */ 108 public boolean isNewCollectionRecord() { 109 return newCollectionRecord; 110 } 111 112 /** 113 * Sets the newCollectionRecord attribute value. 114 * 115 * @param isNewCollectionRecord The newCollectionRecord to set. 116 */ 117 public void setNewCollectionRecord(boolean isNewCollectionRecord) { 118 this.newCollectionRecord = isNewCollectionRecord; 119 } 120 121 /** 122 * Implementation of the OJB afterDelete hook which delegates to {@link #postRemove()}. This method is final 123 * because it is recommended that sub-classes override and implement postRemove if they need to take 124 * advantage of this persistence hook. 125 * 126 * @see org.apache.ojb.broker.PersistenceBrokerAware#afterDelete(org.apache.ojb.broker.PersistenceBroker) 127 */ 128 public final void afterDelete(PersistenceBroker persistenceBroker) throws PersistenceBrokerException { 129 postRemove(); 130 } 131 132 /** 133 * Default implementation of the JPA {@link PostRemove} hook. This implementation currently does nothing, 134 * however sub-classes can override and implement this method if needed. 135 * 136 * <p>This method is currently invoked by the corresponding OJB {@link #afterDelete(PersistenceBroker)} hook. 137 */ 138 @PostRemove 139 protected void postRemove() { 140 // do nothing 141 } 142 143 /** 144 * Implementation of the OJB afterInsert hook which delegates to {@link #postPersist()}. This method is final 145 * because it is recommended that sub-classes override and implement postPersist if they need to take 146 * advantage of this persistence hook. 147 * 148 * @see org.apache.ojb.broker.PersistenceBrokerAware#afterInsert(org.apache.ojb.broker.PersistenceBroker) 149 */ 150 public final void afterInsert(PersistenceBroker persistenceBroker) throws PersistenceBrokerException { 151 postPersist(); 152 } 153 154 /** 155 * Default implementation of the JPA {@link PostPersist} hook. This implementation currently does nothing, 156 * however sub-classes can override and implement this method if needed. 157 * 158 * <p>This method is currently invoked by the corresponding OJB {@link #afterInsert(PersistenceBroker)} hook. 159 */ 160 @PostPersist 161 protected void postPersist() { 162 // do nothing 163 } 164 165 /** 166 * Implementation of the OJB afterLookup hook which delegates to {@link #postLoad()}. This method is final 167 * because it is recommended that sub-classes override and implement postLoad if they need to take 168 * advantage of this persistence hook. 169 * 170 * @see org.apache.ojb.broker.PersistenceBrokerAware#afterLookup(org.apache.ojb.broker.PersistenceBroker) 171 */ 172 public final void afterLookup(PersistenceBroker persistenceBroker) throws PersistenceBrokerException { 173 postLoad(); 174 } 175 176 /** 177 * Default implementation of the JPA {@link PostLoad} hook. This implementation currently does nothing, 178 * however sub-classes can override and implement this method if needed. 179 * 180 * <p>This method is currently invoked by the corresponding OJB {@link #afterLookup(PersistenceBroker)} hook. 181 */ 182 @PostLoad 183 protected void postLoad() { 184 // do nothing 185 } 186 187 /** 188 * Implementation of the OJB afterUpdate hook which delegates to {@link #postUpdate()}. This method is final 189 * because it is recommended that sub-classes override and implement postUpdate if they need to take 190 * advantage of this persistence hook. 191 * 192 * @see org.apache.ojb.broker.PersistenceBrokerAware#afterUpdate(org.apache.ojb.broker.PersistenceBroker) 193 */ 194 public final void afterUpdate(PersistenceBroker persistenceBroker) throws PersistenceBrokerException { 195 postUpdate(); 196 } 197 198 /** 199 * Default implementation of the JPA {@link PostUpdate} hook. This implementation currently does nothing, 200 * however sub-classes can override and implement this method if needed. 201 * 202 * <p>This method is currently invoked by the corresponding OJB {@link #afterUpdate(PersistenceBroker)} hook. 203 */ 204 @PostUpdate 205 protected void postUpdate() { 206 // do nothing 207 } 208 209 /** 210 * Implementation of the OJB beforeDelete hook which delegates to {@link #preRemove()}. This method is final 211 * because it is recommended that sub-classes override and implement preRemove if they need to take 212 * advantage of this persistence hook. 213 * 214 * @see org.apache.ojb.broker.PersistenceBrokerAware#beforeDelete(org.apache.ojb.broker.PersistenceBroker) 215 */ 216 public final void beforeDelete(PersistenceBroker persistenceBroker) throws PersistenceBrokerException { 217 preRemove(); 218 } 219 220 /** 221 * Default implementation of the JPA {@link PreRemove} hook. This implementation currently does nothing, 222 * however sub-classes can implement this method if needed. 223 * 224 * <p>This method is currently invoked by the corresponding OJB {@link #beforeDelete(PersistenceBroker)} hook. 225 */ 226 @PreRemove 227 protected void preRemove() { 228 // do nothing 229 } 230 231 /** 232 * Implementation of the OJB beforeInsert hook which delegates to {@link #prePersist()}. This method is final 233 * because it is recommended that sub-classes override and implement prePersist if they need to take 234 * advantage of this persistence hook. 235 * 236 * @see org.apache.ojb.broker.PersistenceBrokerAware#beforeInsert(org.apache.ojb.broker.PersistenceBroker) 237 */ 238 public final void beforeInsert(PersistenceBroker persistenceBroker) throws PersistenceBrokerException { 239 //setObjectId(UUID.randomUUID().toString()); 240 setObjectId(null); 241 prePersist(); 242 } 243 244 /** 245 * Default implementation of the JPA {@link PrePersist} hook which generates the unique objectId for this 246 * persistable business object if it does not already have one. Any sub-class which overrides this method 247 * should take care to invoke super.prePersist to ensure that the objectId for this persistable 248 * business object is generated properly. 249 * 250 * <p>This method is currently invoked by the corresponding OJB {@link #beforeInsert(PersistenceBroker)} hook. 251 */ 252 @PrePersist 253 protected void prePersist() { 254 generateAndSetObjectIdIfNeeded(); 255 } 256 257 /** 258 * Implementation of the OJB beforeUpdate hook which delegates to {@link #preUpdate()}. This method is final 259 * because it is recommended that sub-classes override and implement preUpdate if they need to take 260 * advantage of this persistence hook. 261 * 262 * @see org.apache.ojb.broker.PersistenceBrokerAware#beforeUpdate(org.apache.ojb.broker.PersistenceBroker) 263 */ 264 public final void beforeUpdate(PersistenceBroker persistenceBroker) throws PersistenceBrokerException { 265 preUpdate(); 266 } 267 268 /** 269 * Default implementation of the JPA {@link PreUpdate} hook which generates the unique objectId for this 270 * persistable business object if it does not already have one. Any sub-class which overrides this method 271 * should take care to invoke super.preUpdate to ensure that the objectId for this persistable 272 * business object is generated properly. 273 * 274 * <p>This method is currently invoked by the corresponding OJB {@link #beforeUpdate(PersistenceBroker)} hook. 275 */ 276 @PreUpdate 277 protected void preUpdate() { 278 generateAndSetObjectIdIfNeeded(); 279 } 280 281 /** 282 * If this PersistableBusinessObject does not already have a unique objectId, this method will generate 283 * one and set it's value on this object. 284 */ 285 private void generateAndSetObjectIdIfNeeded() { 286 if (StringUtils.isEmpty(getObjectId())) { 287 setObjectId(UUID.randomUUID().toString()); 288 } 289 } 290 291 /** 292 * getService Refreshes the reference objects from the primitive values. 293 * 294 * @see org.kuali.rice.krad.bo.BusinessObject#refresh() 295 */ 296 public void refresh() { 297 getPersistenceService().retrieveNonKeyFields(this); 298 } 299 300 /** 301 * @see BusinessObject#refresh() 302 */ 303 public void refreshNonUpdateableReferences() { 304 getPersistenceService().refreshAllNonUpdatingReferences(this); 305 } 306 307 public void refreshReferenceObject(String referenceObjectName) { 308 if ( StringUtils.isNotBlank(referenceObjectName) && !StringUtils.equals(referenceObjectName, "extension")) { 309 final PersistenceStructureService pss = getPersistenceStructureService(); 310 if ( pss.hasReference(this.getClass(), referenceObjectName) || pss.hasCollection(this.getClass(), referenceObjectName)) { 311 getPersistenceService().retrieveReferenceObject( this, referenceObjectName); 312 } else { 313 LOG.warn( "refreshReferenceObject() called with non-reference property: " + referenceObjectName ); 314 } 315 } 316 } 317 318 /** 319 * @see PersistableBusinessObject#buildListOfDeletionAwareLists() 320 */ 321 public List<Collection<PersistableBusinessObject>> buildListOfDeletionAwareLists() { 322 return new ArrayList<Collection<PersistableBusinessObject>>(); 323 } 324 325 public void linkEditableUserFields() { 326 // do nothing 327 } 328 329 public PersistableBusinessObjectExtension getExtension() { 330 if ( extension == null ) { 331 try { 332 Class<? extends PersistableBusinessObjectExtension> extensionClass = getPersistenceStructureService().getBusinessObjectAttributeClass( getClass(), "extension" ); 333 if ( extensionClass != null ) { 334 extension = extensionClass.newInstance(); 335 } 336 } catch ( Exception ex ) { 337 LOG.error( "unable to create extension object", ex ); 338 } 339 } 340 return extension; 341 } 342 343 public void setExtension(PersistableBusinessObjectExtension extension) { 344 this.extension = extension; 345 } 346 347 /** 348 * @return the persistenceService 349 */ 350 protected static PersistenceService getPersistenceService() { 351 if ( persistenceService == null ) { 352 persistenceService = KRADServiceLocator.getPersistenceService(); 353 } 354 return persistenceService; 355 } 356 357 protected static PersistenceStructureService getPersistenceStructureService() { 358 if ( persistenceStructureService == null ) { 359 persistenceStructureService = KRADServiceLocator.getPersistenceStructureService(); 360 } 361 return persistenceStructureService; 362 } 363 364 }