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 java.io.Serializable;
19 import java.lang.reflect.Field;
20 import java.util.UUID;
21
22 import javax.persistence.Column;
23 import javax.persistence.Embeddable;
24 import javax.persistence.MappedSuperclass;
25 import javax.persistence.PrePersist;
26 import javax.persistence.PreUpdate;
27 import javax.persistence.Transient;
28 import javax.persistence.Version;
29
30 import org.apache.commons.lang.StringUtils;
31 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
32 import org.kuali.rice.core.api.mo.common.GloballyUnique;
33 import org.kuali.rice.core.api.mo.common.Versioned;
34
35 /**
36 * Declares an optional superclass for classes which can have their
37 * state persisted. A data object which is persistable defines some additional methods
38 * which allow for various operations to be executed that relate to the persistent nature of
39 * the data object. A persistable data object also has some additional data
40 * attributes which include the version number, the object id, and the extension.
41 *
42 * <p>The version number indicates the version of the data object when it was retrieved
43 * from persistent storage. This allows for services to check this version number
44 * during persistence operations to prevent silent overwrites of data object state.
45 * These kinds of scenarios might arise as a result of concurrent modification to the data
46 * object in the persistent store (i.e. two web application users updating the same record
47 * in a database). The kind of check which would be performed using the version number is commonly
48 * referred to as "optimistic locking".
49 *
50 * <p>The object id represents a globally unique identifier for the business object. In practice,
51 * this can be used by other portions of the system to link to data objects which
52 * might be stored in different locations or even different persistent data stores. In general, it
53 * is not the responsibility of the client who implements a persistable data object to handle
54 * generating this value. The framework will handle this automatically at the point in time when
55 * the data object is persisted. If the client does need to do this themselves, however, care
56 * should be taken that an appropriate globally unique value generator algorithm is used
57 * (such as the one provided by {@link UUID}).
58 *
59 * <p>The extension object is primarily provided for the purposes of allowing implementer
60 * customization of the data object without requiring the original data object to be
61 * modified. The additional extension object which is linked with the
62 * parent data object via use of {@link org.kuali.rice.krad.data.provider.annotation.ExtensionFor}
63 * annotation on the actual extension class} can contain additional data attributes and methods.
64 * The framework will automatically request that this extension object be persisted when the parent
65 * data object is persisted. This is generally the most useful in cases where an application is defining
66 * data objects that will be used in redistributable software packages (such as the
67 * actual Kuali Foundation projects themselves). If using the framework for the purposes
68 * of implementing an internal application, the use of a data object extensions
69 * is likely unnecessary.
70 *
71 * @author Kuali Rice Team (rice.collab@kuali.org)
72 */
73 @MappedSuperclass
74 public abstract class DataObjectBase implements Versioned, GloballyUnique, Serializable {
75
76 /**
77 * EclipseLink static weaving does not weave MappedSuperclass unless an Entity or Embedded is
78 * weaved which uses it, hence this class.
79 */
80 @Embeddable
81 private static final class WeaveMe extends DataObjectBase {}
82
83 @Version
84 @Column(name="VER_NBR", length=8)
85 protected Long versionNumber;
86
87 @Column(name="OBJ_ID", length=36, unique=true, nullable = false)
88 protected String objectId;
89
90 @Transient
91 Object extensionObject;
92
93 @Override
94 public Long getVersionNumber() {
95 return versionNumber;
96 }
97
98 public void setVersionNumber(Long versionNumber) {
99 this.versionNumber = versionNumber;
100 }
101
102
103 /**
104 * getter for the guid based object id that is assignable to all objects, in order to support custom attributes a mapping must
105 * also be added to the OJB file and a column must be added to the database for each business object that extension attributes
106 * are supposed to work on.
107 *
108 * @return
109 */
110 @Override
111 public String getObjectId() {
112 return objectId;
113 }
114
115 /**
116 * setter for the guid based object id that is assignable to all objects, in order to support custom attributes a mapping must
117 * also be added to the OJB file and column must be added to the database for each business object that extension attributes are
118 * supposed to work on.
119 *
120 * @param objectId
121 */
122 public void setObjectId(String objectId) {
123 this.objectId = objectId;
124 }
125
126 /**
127 * Default implementation of the JPA {@link PrePersist} hook which generates the unique objectId for this
128 * persistable business object if it does not already have one. Any sub-class which overrides this method
129 * should take care to invoke super.prePersist to ensure that the objectId for this persistable
130 * business object is generated properly.
131 *
132 * <p>This method is currently invoked by the corresponding OJB {@link #beforeInsert(PersistenceBroker)} hook.
133 */
134 @PrePersist
135 protected void prePersist() {
136 generateAndSetObjectIdIfNeeded();
137 }
138
139 /**
140 * Default implementation of the JPA {@link PreUpdate} hook which generates the unique objectId for this
141 * persistable business object if it does not already have one. Any sub-class which overrides this method
142 * should take care to invoke super.preUpdate to ensure that the objectId for this persistable
143 * business object is generated properly.
144 *
145 * <p>This method is currently invoked by the corresponding OJB {@link #beforeUpdate(PersistenceBroker)} hook.
146 */
147 @PreUpdate
148 protected void preUpdate() {
149 generateAndSetObjectIdIfNeeded();
150 }
151
152 /**
153 * If this PersistableBusinessObject does not already have a unique objectId, this method will generate
154 * one and set it's value on this object.
155 */
156 protected void generateAndSetObjectIdIfNeeded() {
157 if (StringUtils.isEmpty(getObjectId())) {
158 setObjectId(UUID.randomUUID().toString());
159 }
160 }
161
162 public Object getExtensionObject() {
163 return extensionObject;
164 }
165
166 public void setExtensionObject(Object extensionObject) {
167 this.extensionObject = extensionObject;
168 }
169
170 @Override
171 public String toString() {
172 class DataObjectToStringBuilder extends ReflectionToStringBuilder {
173 private DataObjectToStringBuilder(Object object) {
174 super(object);
175 }
176
177 @Override
178 public boolean accept(Field field) {
179 if (field.getType().isPrimitive()
180 || field.getType().isEnum()
181 || java.lang.String.class.isAssignableFrom(field.getType())
182 || java.lang.Number.class.isAssignableFrom(field.getType())
183 || java.util.Collection.class.isAssignableFrom(field.getType())) {
184 return super.accept(field);
185 }
186 return false;
187 }
188 };
189 return new DataObjectToStringBuilder(this).toString();
190 }
191
192 }