001 package edu.rice.cs.cunit.instrumentors.threadCheck;
002
003 import edu.rice.cs.cunit.threadCheck.OnlyRunBy;
004 import edu.rice.cs.cunit.threadCheck.SuppressSubtypingWarning;
005
006 import java.io.Serializable;
007 import java.util.HashSet;
008 import java.util.ArrayList;
009
010 /**
011 * Class that keeps track of what thread names/ids/groups are allowed and denied for a method.
012 */
013 public class ThreadCheckAnnotationRecord implements Serializable {
014 public HashSet<String> denyThreadNames;
015 public HashSet<Long> denyThreadIds;
016 public HashSet<String> denyThreadGroups;
017 public HashSet<String> allowThreadNames;
018 public HashSet<Long> allowThreadIds;
019 public HashSet<String> allowThreadGroups;
020 public OnlyRunBy.EVENT_THREAD allowEventThread;
021
022 public ArrayList<PredicateAnnotationRecord> predicateAnnotations;
023
024 public boolean suppressSubtypingWarning = false;
025
026 /** Timestamp of the last modification. */
027 public long timeStamp;
028
029 /**
030 * Create a new empty annotation record.
031 */
032 public ThreadCheckAnnotationRecord() {
033 denyThreadNames = new HashSet<String>();
034 denyThreadIds = new HashSet<Long>();
035 denyThreadGroups = new HashSet<String>();
036 allowThreadNames = new HashSet<String>();
037 allowThreadIds = new HashSet<Long>();
038 allowThreadGroups = new HashSet<String>();
039 allowEventThread = OnlyRunBy.EVENT_THREAD.NO;
040 predicateAnnotations = new ArrayList<PredicateAnnotationRecord>();
041 timeStamp = System.currentTimeMillis();
042 }
043
044 /**
045 * Create a new annotation record by merging the two specified records
046 * @param firstAR first record to merge
047 * @param secondAR second record to merge
048 */
049 public ThreadCheckAnnotationRecord(ThreadCheckAnnotationRecord firstAR,
050 ThreadCheckAnnotationRecord secondAR) {
051 denyThreadNames = new HashSet<String>(firstAR.denyThreadNames);
052 denyThreadNames.addAll(secondAR.denyThreadNames);
053 denyThreadIds = new HashSet<Long>(firstAR.denyThreadIds);
054 denyThreadIds.addAll(secondAR.denyThreadIds);
055 denyThreadGroups = new HashSet<String>(firstAR.denyThreadGroups);
056 denyThreadGroups.addAll(secondAR.denyThreadGroups);
057 allowThreadNames = new HashSet<String>(firstAR.allowThreadNames);
058 allowThreadNames.addAll(secondAR.allowThreadNames);
059 allowThreadIds = new HashSet<Long>(firstAR.allowThreadIds);
060 allowThreadIds.addAll(secondAR.allowThreadIds);
061 allowThreadGroups = new HashSet<String>(firstAR.allowThreadGroups);
062 allowThreadGroups.addAll(secondAR.allowThreadGroups);
063 if (firstAR.allowEventThread.compareTo(secondAR.allowEventThread)>=0) {
064 allowEventThread = firstAR.allowEventThread;
065 }
066 else {
067 allowEventThread = secondAR.allowEventThread;
068 }
069 predicateAnnotations = new ArrayList<PredicateAnnotationRecord>(firstAR.predicateAnnotations);
070 predicateAnnotations.addAll(predicateAnnotations);
071 timeStamp = Math.max(firstAR.timeStamp, secondAR.timeStamp);
072 suppressSubtypingWarning = firstAR.suppressSubtypingWarning || secondAR.suppressSubtypingWarning;
073 }
074
075 /**
076 * Adds the annotations in the other annotation record to this one
077 * @param otherAR other record
078 */
079 public void add(ThreadCheckAnnotationRecord otherAR) {
080 denyThreadNames.addAll(otherAR.denyThreadNames);
081 denyThreadIds.addAll(otherAR.denyThreadIds);
082 denyThreadGroups.addAll(otherAR.denyThreadGroups);
083 allowThreadNames.addAll(otherAR.allowThreadNames);
084 allowThreadIds.addAll(otherAR.allowThreadIds);
085 allowThreadGroups.addAll(otherAR.allowThreadGroups);
086 if (otherAR.allowEventThread.compareTo(allowEventThread)>0) {
087 allowEventThread = otherAR.allowEventThread;
088 }
089 predicateAnnotations.addAll(otherAR.predicateAnnotations);
090 timeStamp = Math.max(timeStamp, otherAR.timeStamp);
091 suppressSubtypingWarning = suppressSubtypingWarning || otherAR.suppressSubtypingWarning;
092 }
093
094 /**
095 * Return true if there is nothing specified in this annotation record.
096 * @return true if nothing specified
097 */
098 public boolean empty() {
099 return (denyThreadNames.size()==0) &&
100 (denyThreadIds.size()==0) &&
101 (denyThreadGroups.size()==0) &&
102 (allowThreadNames.size()==0) &&
103 (allowThreadIds.size()==0) &&
104 (allowThreadGroups.size()==0) &&
105 (allowEventThread==OnlyRunBy.EVENT_THREAD.NO) &&
106 (predicateAnnotations.size()==0);
107 }
108
109 // /**
110 // * Returns true if the two ThreadCheckAnnotationRecords are equal.
111 // * @param o other object
112 // * @return true if equal
113 // */
114 // public boolean equals(Object o) {
115 // if (this == o) {
116 // return true;
117 // }
118 // if (o == null || getClass() != o.getClass()) {
119 // return false;
120 // }
121 //
122 // ThreadCheckAnnotationRecord that = (ThreadCheckAnnotationRecord)o;
123 //
124 // if (allowEventThread != that.allowEventThread) {
125 // return false;
126 // }
127 // if (!allowThreadGroups.equals(that.allowThreadGroups)) {
128 // return false;
129 // }
130 // if (!allowThreadIds.equals(that.allowThreadIds)) {
131 // return false;
132 // }
133 // if (!allowThreadNames.equals(that.allowThreadNames)) {
134 // return false;
135 // }
136 // if (!denyThreadGroups.equals(that.denyThreadGroups)) {
137 // return false;
138 // }
139 // if (!denyThreadIds.equals(that.denyThreadIds)) {
140 // return false;
141 // }
142 // if (!denyThreadNames.equals(that.denyThreadNames)) {
143 // return false;
144 // }
145 // if (!predicateAnnotations.equals(that.predicateAnnotations)) {
146 // return false;
147 // }
148 //
149 // return true;
150 // }
151 //
152 // /**
153 // * Returns a hashcode for this ThreadCheckAnnotationRecord.
154 // * @return hashcode
155 // */
156 // public int hashCode() {
157 // int result;
158 // result = denyThreadNames.hashCode();
159 // result = 31 * result + denyThreadIds.hashCode();
160 // result = 31 * result + denyThreadGroups.hashCode();
161 // result = 31 * result + allowThreadNames.hashCode();
162 // result = 31 * result + allowThreadIds.hashCode();
163 // result = 31 * result + allowThreadGroups.hashCode();
164 // result = 31 * result + allowEventThread.hashCode();
165 // result = 31 * result + predicateAnnotations.hashCode();
166 // return result;
167 // }
168
169
170 /**
171 * Returns true if the two ThreadCheckAnnotationRecords are equal.
172 * @param o other object
173 * @return true if equal
174 */
175 public boolean equals(Object o) {
176 if (this == o) {
177 return true;
178 }
179 if (o == null || getClass() != o.getClass()) {
180 return false;
181 }
182
183 ThreadCheckAnnotationRecord that = (ThreadCheckAnnotationRecord)o;
184
185 if (suppressSubtypingWarning != that.suppressSubtypingWarning) {
186 return false;
187 }
188 if (allowEventThread != that.allowEventThread) {
189 return false;
190 }
191 if (allowThreadGroups != null ? !allowThreadGroups.equals(that.allowThreadGroups) :
192 that.allowThreadGroups != null) {
193 return false;
194 }
195 if (allowThreadIds != null ? !allowThreadIds.equals(that.allowThreadIds) : that.allowThreadIds != null) {
196 return false;
197 }
198 if (allowThreadNames != null ? !allowThreadNames.equals(that.allowThreadNames) :
199 that.allowThreadNames != null) {
200 return false;
201 }
202 if (denyThreadGroups != null ? !denyThreadGroups.equals(that.denyThreadGroups) :
203 that.denyThreadGroups != null) {
204 return false;
205 }
206 if (denyThreadIds != null ? !denyThreadIds.equals(that.denyThreadIds) : that.denyThreadIds != null) {
207 return false;
208 }
209 if (denyThreadNames != null ? !denyThreadNames.equals(that.denyThreadNames) :
210 that.denyThreadNames != null) {
211 return false;
212 }
213 if (predicateAnnotations != null ? !predicateAnnotations.equals(that.predicateAnnotations) :
214 that.predicateAnnotations != null) {
215 return false;
216 }
217
218 return true;
219 }
220
221 /**
222 * Returns a hashcode for this ThreadCheckAnnotationRecord.
223 * @return hashcode
224 */
225 public int hashCode() {
226 int result;
227 result = (denyThreadNames != null ? denyThreadNames.hashCode() : 0);
228 result = 31 * result + (denyThreadIds != null ? denyThreadIds.hashCode() : 0);
229 result = 31 * result + (denyThreadGroups != null ? denyThreadGroups.hashCode() : 0);
230 result = 31 * result + (allowThreadNames != null ? allowThreadNames.hashCode() : 0);
231 result = 31 * result + (allowThreadIds != null ? allowThreadIds.hashCode() : 0);
232 result = 31 * result + (allowThreadGroups != null ? allowThreadGroups.hashCode() : 0);
233 result = 31 * result + (allowEventThread != null ? allowEventThread.hashCode() : 0);
234 result = 31 * result + (predicateAnnotations != null ? predicateAnnotations.hashCode() : 0);
235 result = 31 * result + (suppressSubtypingWarning ? 1 : 0);
236 return result;
237 }
238
239 /**
240 * Returns a string representation of the object.
241 * @return a string representation of the object.
242 */
243 public String toString() {
244 if (empty()) { return ""; }
245 String LF = System.getProperty("line.separator");
246 StringBuilder sb = new StringBuilder();
247 if (suppressSubtypingWarning) {
248 sb.append('@');
249 sb.append(SuppressSubtypingWarning.class.getSimpleName());
250 sb.append(LF);
251 }
252 if ((denyThreadNames.size()>0) ||
253 (denyThreadGroups.size()>0) ||
254 (denyThreadIds.size()>0)) {
255 StringBuilder sbNot = new StringBuilder();
256 for(String s: denyThreadNames) {
257 sbNot.append(',');
258 sbNot.append(LF);
259 sbNot.append("\t@ThreadDesc(name=\"");
260 sbNot.append(s);
261 sbNot.append("\")");
262 }
263 for(String s: denyThreadGroups) {
264 sbNot.append(',');
265 sbNot.append(LF);
266 sbNot.append("\t@ThreadDesc(group=\"");
267 sbNot.append(s);
268 sbNot.append("\")");
269 }
270 for(Long l: denyThreadIds) {
271 sbNot.append(',');
272 sbNot.append(LF);
273 sbNot.append("\t@ThreadDesc(id=");
274 sbNot.append(l);
275 sbNot.append(")");
276 }
277 sbNot.append(LF);
278 sbNot.append("})");
279
280 sbNot.deleteCharAt(0); // delete first ','
281
282 sb.append("@NotRunBy({");
283 sb.append(sbNot.toString());
284 }
285
286 if ((allowThreadNames.size()>0) ||
287 (allowThreadGroups.size()>0) ||
288 (allowThreadIds.size()>0) ||
289 allowEventThread!=OnlyRunBy.EVENT_THREAD.NO) {
290 if (sb.length()>0) {
291 sb.append(LF);
292 }
293
294 StringBuilder sbOnly = new StringBuilder();
295 for(String s: allowThreadNames) {
296 sbOnly.append(',');
297 sbOnly.append(LF);
298 sbOnly.append("\t@ThreadDesc(name=\"");
299 sbOnly.append(s);
300 sbOnly.append("\")");
301 }
302 for(String s: allowThreadGroups) {
303 sbOnly.append(',');
304 sbOnly.append(LF);
305 sbOnly.append("\t@ThreadDesc(group=\"");
306 sbOnly.append(s);
307 sbOnly.append("\")");
308 }
309 for(Long l: allowThreadIds) {
310 sbOnly.append(',');
311 sbOnly.append(LF);
312 sbOnly.append("\t@ThreadDesc(id=");
313 sbOnly.append(l);
314 sbOnly.append(")");
315 }
316 if (allowEventThread==OnlyRunBy.EVENT_THREAD.ONLY) {
317 sbOnly.append(',');
318 sbOnly.append(LF);
319 sbOnly.append("\t@ThreadDesc(eventThread=OnlyRunBy.EVENT_THREAD.ONLY)");
320 }
321 else if (allowEventThread==OnlyRunBy.EVENT_THREAD.ONLY_AFTER_REALIZED) {
322 sbOnly.append(',');
323 sbOnly.append(LF);
324 sbOnly.append("\t@ThreadDesc(eventThread=OnlyRunBy.EVENT_THREAD.ONLY_AFTER_REALIZED)");
325 }
326 sbOnly.append(LF);
327 sbOnly.append("})");
328
329 sbOnly.deleteCharAt(0); // delete first ','
330
331 sb.append("@OnlyRunBy({");
332 sb.append(sbOnly.toString());
333 }
334
335 if (predicateAnnotations.size()>0) {
336 if (sb.length()>0) {
337 sb.append(LF);
338 }
339 boolean notFirst = false;
340 for(PredicateAnnotationRecord pa: predicateAnnotations) {
341 if (notFirst) { sb.append(LF); } else { notFirst = true; }
342 sb.append(pa.toString());
343 }
344 }
345
346 return sb.toString();
347 }
348 }