1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.kuali.rice.core.api.mo;
17  
18  import org.apache.commons.lang.builder.EqualsBuilder;
19  import org.apache.commons.lang.builder.HashCodeBuilder;
20  import org.apache.commons.lang.builder.ToStringBuilder;
21  import org.kuali.rice.core.api.CoreConstants;
22  import org.kuali.rice.core.api.util.collect.CollectionUtils;
23  
24  import javax.xml.bind.Unmarshaller;
25  import javax.xml.bind.annotation.XmlTransient;
26  import java.io.IOException;
27  import java.io.ObjectInputStream;
28  import java.io.ObjectOutputStream;
29  import java.lang.reflect.Field;
30  import java.util.Arrays;
31  import java.util.Collection;
32  import java.util.Collections;
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  @XmlTransient 
49  public abstract class AbstractDataTransferObject implements ModelObjectComplete {
50  
51      private transient volatile Integer _hashCode;
52      private transient volatile String _toString;
53  
54      protected AbstractDataTransferObject() {
55          super();
56      }
57  
58      
59  
60  
61  
62  
63  
64  
65      protected final int hashCodeExcludeFields(Collection<String> excludedFields) {
66          
67          
68          Integer h = _hashCode;
69          if (h == null) {
70              synchronized (this) {
71                  h = _hashCode;
72                  if (h == null) {
73                      _hashCode = h = Integer.valueOf(HashCodeBuilder.reflectionHashCode(this, excludedFields));
74                  }
75              }
76          }
77  
78          return h.intValue();
79      }
80  
81      @Override
82      public int hashCode() {
83          return hashCodeExcludeFields(Constants.hashCodeEqualsExclude);
84      }
85  
86      
87  
88  
89  
90  
91  
92  
93  
94  
95      protected final boolean equalsExcludeFields(Object obj, Collection<String> excludedFields) {
96          return EqualsBuilder.reflectionEquals(obj, this, excludedFields);
97      }
98  
99      @Override
100     public boolean equals(Object obj) {
101         return equalsExcludeFields(obj, Constants.hashCodeEqualsExclude);
102     }
103 
104     @Override
105     public String toString() {
106         
107         
108         String t = _toString;
109         if (t == null) {
110             synchronized (this) {
111                 t = _toString;
112                 if (t == null) {
113                     _toString = t = ToStringBuilder.reflectionToString(this);
114                 }
115             }
116         }
117 
118         return t;
119     }
120 
121     @SuppressWarnings("unused")
122     protected void beforeUnmarshal(Unmarshaller u, Object parent) throws Exception {
123     }
124 
125     @SuppressWarnings("unused")
126     protected void afterUnmarshal(Unmarshaller u, Object parent) throws Exception {
127         CollectionUtils.makeUnmodifiableAndNullSafe(this);
128     }
129 
130     private transient Object serializationMutex = new Object();
131 
132     private void writeObject(ObjectOutputStream out) throws IOException {
133         synchronized (serializationMutex) {
134             clearFutureElements();
135             out.defaultWriteObject();
136         }
137     }
138 
139     private void readObject(ObjectInputStream ois) throws IOException,
140             ClassNotFoundException {
141         ois.defaultReadObject();
142         serializationMutex = new Object();
143     }
144 
145     
146 
147 
148 
149     private void clearFutureElements() {
150         try {
151             Field futureElementsField = getClass().getDeclaredField(CoreConstants.CommonElements.FUTURE_ELEMENTS);
152             boolean originalAccessible = futureElementsField.isAccessible();
153             futureElementsField.setAccessible(true);
154             try {
155                 futureElementsField.set(this, null);
156             } finally {
157                 futureElementsField.setAccessible(originalAccessible);
158             }
159         } catch (NoSuchFieldException e) {
160             
161         } catch (IllegalAccessException e) {
162             
163         }
164     }
165 
166 
167     
168 
169 
170     protected static class Constants {
171         final static Collection<String> hashCodeEqualsExclude = Collections.unmodifiableCollection(
172                 Arrays.asList(CoreConstants.CommonElements.FUTURE_ELEMENTS, "_hashCode", "_toString")
173         );
174     }
175 
176     protected static final Collection<String> getDefaultHashCodeEqualsExcludeFields() {
177         return Constants.hashCodeEqualsExclude;
178     }
179 }