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