1 /**
2 * Copyright 2005-2014 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 && 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 }