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 }