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 prePersist(); 240 } 241 242 /** 243 * Default implementation of the JPA {@link PrePersist} hook which generates the unique objectId for this 244 * persistable business object if it does not already have one. Any sub-class which overrides this method 245 * should take care to invoke super.prePersist to ensure that the objectId for this persistable 246 * business object is generated properly. 247 * 248 * <p>This method is currently invoked by the corresponding OJB {@link #beforeInsert(PersistenceBroker)} hook. 249 */ 250 @PrePersist 251 protected void prePersist() { 252 generateAndSetObjectIdIfNeeded(); 253 } 254 255 /** 256 * Implementation of the OJB beforeUpdate hook which delegates to {@link #preUpdate()}. This method is final 257 * because it is recommended that sub-classes override and implement preUpdate if they need to take 258 * advantage of this persistence hook. 259 * 260 * @see org.apache.ojb.broker.PersistenceBrokerAware#beforeUpdate(org.apache.ojb.broker.PersistenceBroker) 261 */ 262 public final void beforeUpdate(PersistenceBroker persistenceBroker) throws PersistenceBrokerException { 263 preUpdate(); 264 } 265 266 /** 267 * Default implementation of the JPA {@link PreUpdate} hook which generates the unique objectId for this 268 * persistable business object if it does not already have one. Any sub-class which overrides this method 269 * should take care to invoke super.preUpdate to ensure that the objectId for this persistable 270 * business object is generated properly. 271 * 272 * <p>This method is currently invoked by the corresponding OJB {@link #beforeUpdate(PersistenceBroker)} hook. 273 */ 274 @PreUpdate 275 protected void preUpdate() { 276 generateAndSetObjectIdIfNeeded(); 277 } 278 279 /** 280 * If this PersistableBusinessObject does not already have a unique objectId, this method will generate 281 * one and set it's value on this object. 282 */ 283 private void generateAndSetObjectIdIfNeeded() { 284 if (StringUtils.isEmpty(getObjectId())) { 285 setObjectId(UUID.randomUUID().toString()); 286 } 287 } 288 289 /** 290 * getService Refreshes the reference objects from the primitive values. 291 * 292 * @see org.kuali.rice.kns.bo.BusinessObject#refresh() 293 */ 294 public void refresh() { 295 getPersistenceService().retrieveNonKeyFields(this); 296 } 297 298 /** 299 * @see BusinessObject#refresh() 300 */ 301 public void refreshNonUpdateableReferences() { 302 getPersistenceService().refreshAllNonUpdatingReferences(this); 303 } 304 305 public void refreshReferenceObject(String referenceObjectName) { 306 if ( StringUtils.isNotBlank(referenceObjectName) && !StringUtils.equals(referenceObjectName, "extension")) { 307 final PersistenceStructureService pss = getPersistenceStructureService(); 308 if ( pss.hasReference(this.getClass(), referenceObjectName) || pss.hasCollection(this.getClass(), referenceObjectName)) { 309 getPersistenceService().retrieveReferenceObject( this, referenceObjectName); 310 } else { 311 LOG.warn( "refreshReferenceObject() called with non-reference property: " + referenceObjectName ); 312 } 313 } 314 } 315 316 /** 317 * @see PersistableBusinessObject#buildListOfDeletionAwareLists() 318 */ 319 public List<Collection<PersistableBusinessObject>> buildListOfDeletionAwareLists() { 320 return new ArrayList<Collection<PersistableBusinessObject>>(); 321 } 322 323 public void linkEditableUserFields() { 324 // do nothing 325 } 326 327 public PersistableBusinessObjectExtension getExtension() { 328 if ( extension == null ) { 329 try { 330 Class<? extends PersistableBusinessObjectExtension> extensionClass = getPersistenceStructureService().getBusinessObjectAttributeClass( getClass(), "extension" ); 331 if ( extensionClass != null ) { 332 extension = extensionClass.newInstance(); 333 } 334 } catch ( Exception ex ) { 335 LOG.error( "unable to create extension object", ex ); 336 } 337 } 338 return extension; 339 } 340 341 public void setExtension(PersistableBusinessObjectExtension extension) { 342 this.extension = extension; 343 } 344 345 /** 346 * @return the persistenceService 347 */ 348 protected static PersistenceService getPersistenceService() { 349 if ( persistenceService == null ) { 350 persistenceService = KRADServiceLocator.getPersistenceService(); 351 } 352 return persistenceService; 353 } 354 355 protected static PersistenceStructureService getPersistenceStructureService() { 356 if ( persistenceStructureService == null ) { 357 persistenceStructureService = KRADServiceLocator.getPersistenceStructureService(); 358 } 359 return persistenceStructureService; 360 } 361 362 }