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 }