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 }