001/** 002 * Copyright 2005-2016 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.bo; 017 018import org.apache.commons.lang.StringUtils; 019import org.apache.ojb.broker.PersistenceBroker; 020import org.apache.ojb.broker.PersistenceBrokerAware; 021import org.apache.ojb.broker.PersistenceBrokerException; 022import org.kuali.rice.core.api.mo.common.GloballyUnique; 023import org.kuali.rice.core.api.mo.common.Versioned; 024import org.kuali.rice.krad.service.KRADServiceLocator; 025import org.kuali.rice.krad.service.PersistenceService; 026import org.kuali.rice.krad.service.PersistenceStructureService; 027 028import javax.persistence.Column; 029import javax.persistence.MappedSuperclass; 030import javax.persistence.PostLoad; 031import javax.persistence.PostPersist; 032import javax.persistence.PostRemove; 033import javax.persistence.PostUpdate; 034import javax.persistence.PrePersist; 035import javax.persistence.PreRemove; 036import javax.persistence.PreUpdate; 037import javax.persistence.Transient; 038import javax.persistence.Version; 039import java.util.ArrayList; 040import java.util.Collection; 041import java.util.List; 042import java.util.UUID; 043 044/** 045 * @author Kuali Rice Team (rice.collab@kuali.org) 046 */ 047@MappedSuperclass 048public abstract class PersistableBusinessObjectBase extends BusinessObjectBase implements PersistableBusinessObject, PersistenceBrokerAware, Versioned, GloballyUnique { 049 private static final long serialVersionUID = 1451642350593233282L; 050 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PersistableBusinessObjectBase.class); 051 052 @Version 053 @Column(name="VER_NBR") 054 protected Long versionNumber; 055 @Column(name="OBJ_ID") 056 private String objectId; 057 @Transient 058 private boolean newCollectionRecord; 059 @Transient 060 protected PersistableBusinessObjectExtension extension; 061 062 private static transient PersistenceService persistenceService; 063 private static transient PersistenceStructureService persistenceStructureService; 064 065 /** 066 * @see PersistableBusinessObject#getVersionNumber() 067 */ 068 public Long getVersionNumber() { 069 return versionNumber; 070 } 071 072 /** 073 * @see PersistableBusinessObject#getVersionNumber() 074 */ 075 public void setVersionNumber(Long versionNumber) { 076 this.versionNumber = versionNumber; 077 } 078 079 080 /** 081 * getter for the guid based object id that is assignable to all objects, in order to support custom attributes a mapping must 082 * also be added to the OJB file and a column must be added to the database for each business object that extension attributes 083 * are supposed to work on. 084 * 085 * @return 086 */ 087 public String getObjectId() { 088 return objectId; 089 } 090 091 /** 092 * setter for the guid based object id that is assignable to all objects, in order to support custom attributes a mapping must 093 * also be added to the OJB file and column must be added to the database for each business object that extension attributes are 094 * supposed to work on. 095 * 096 * @param objectId 097 */ 098 public void setObjectId(String objectId) { 099 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 && getPersistenceStructureService().isPersistable(this.getClass())) { 332 try { 333 Class<? extends PersistableBusinessObjectExtension> extensionClass = getPersistenceStructureService().getBusinessObjectAttributeClass( getClass(), "extension" ); 334 if ( extensionClass != null ) { 335 extension = extensionClass.newInstance(); 336 } 337 } catch ( Exception ex ) { 338 LOG.error( "unable to create extension object", ex ); 339 } 340 } 341 return extension; 342 } 343 344 public void setExtension(PersistableBusinessObjectExtension extension) { 345 this.extension = extension; 346 } 347 348 /** 349 * @return the persistenceService 350 */ 351 protected static PersistenceService getPersistenceService() { 352 if ( persistenceService == null ) { 353 persistenceService = KRADServiceLocator.getPersistenceService(); 354 } 355 return persistenceService; 356 } 357 358 protected static PersistenceStructureService getPersistenceStructureService() { 359 if ( persistenceStructureService == null ) { 360 persistenceStructureService = KRADServiceLocator.getPersistenceStructureService(); 361 } 362 return persistenceStructureService; 363 } 364 365}