001    package edu.rice.cs.cunit.instrumentors.threadCheck;
002    
003    import edu.rice.cs.cunit.util.XMLConfig;
004    
005    import java.io.Serializable;
006    import java.util.HashSet;
007    import java.util.HashMap;
008    
009    /**
010         * Class that keeps track an invariant (ThreadCheckAnnotationRecord) and the classes and methods its applied to.
011     */
012    public class ThreadCheckDefinitionRecord implements Serializable {
013        /**
014         * The invariant applied to the classes and methods below.
015         */
016        public final ThreadCheckAnnotationRecord invariant;
017    
018        /**
019         * A set of class names.
020         */
021        public final HashSet<String> classNames;
022    
023        /**
024         * A map of method strings, generated by concatenating the class name, "::" and the method signature.
025         * Example: The method "void run()" in the class "sample.threadCheck.ThreadCheckSample4" has the string
026         * "sample.threadCheck.ThreadCheckSample4::run()V".
027         * The value is true if subtyping warnings should be suppressed.
028         */
029        public final HashMap<String,Boolean> methodClassAndSigs;
030    
031        /**
032         * Create a new empty definition record that just specifies the invariant.
033         * @param inv the invariant of this definition
034         */
035        public ThreadCheckDefinitionRecord(ThreadCheckAnnotationRecord inv) {
036            invariant = inv;
037            classNames = new HashSet<String>();
038            methodClassAndSigs = new HashMap<String,Boolean>();
039        }
040    
041        /**
042         * Add the specified class to the set of classes.
043         * @param className name of the class
044         */
045        public void addClass(String className) {
046            classNames.add(className);
047        }
048    
049        /**
050         * Add the specified method to the set of methods.
051         * @param className name of the class
052         * @param methodSig signature of the method
053         * @param suppressSubtypingWarning true if subtyping warnings should be suppressed
054         */
055        public void addMethod(String className, String methodSig, boolean suppressSubtypingWarning) {
056            methodClassAndSigs.put(className+AThreadCheckStrategy.CLASS_SIG_SEPARATOR_STRING+methodSig, suppressSubtypingWarning);
057        }
058    
059        /**
060         * Return true if the invariant applies to the specified class.
061         * @param className name of the class
062         * @return true if the invariant applies
063         */
064        public boolean appliesToClass(String className) {
065            return classNames.contains(className);
066        }
067    
068        /**
069         * Return true if the invariant applies to the specified method.
070         * @param className name of the class
071         * @param methodSig signature of the method
072         * @return true if the invariant applies
073         */
074        public boolean appliesToMethod(String className, String methodSig) {
075            return methodClassAndSigs.keySet().contains(className+AThreadCheckStrategy.CLASS_SIG_SEPARATOR_STRING +methodSig);
076        }
077    
078        /**
079         * Return the invariant of this definition.
080         * @return the invariant, a ThreadCheckAnnotationRecord
081         */
082        public ThreadCheckAnnotationRecord getInvariant() {
083            return invariant;
084        }
085    
086        /**
087         * Return true if there is nothing specified in this definition record.
088         * @return true if nothing specified
089         */
090        public boolean empty() {
091            return (classNames.size()==0) && (methodClassAndSigs.size()==0);
092        }
093    
094    //        /**
095    //         * Returns true if the two ThreadCheckDefinitionRecords are equal.
096    //         * @param o other object
097    //         * @return true if equal
098    //         */
099    //        public boolean equals(Object o) {
100    //            if (this == o) {
101    //                return true;
102    //            }
103    //            if (o == null || getClass() != o.getClass()) {
104    //                return false;
105    //            }
106    //
107    //            ThreadCheckDefinitionRecord that = (ThreadCheckDefinitionRecord)o;
108    //
109    //            if (!classNames.equals(that.classNames)) {
110    //                return false;
111    //            }
112    //            if (!invariant.equals(that.invariant)) {
113    //                return false;
114    //            }
115    //            if (!methodClassAndSigs.equals(that.methodClassAndSigs)) {
116    //                return false;
117    //            }
118    //
119    //            return true;
120    //        }
121    //
122    //        /**
123    //         * Return a hashcode for this ThreadCheckDefinitionRecord.
124    //         * @return hashcode
125    //         */
126    //        public int hashCode() {
127    //            int result;
128    //            result = invariant.hashCode();
129    //            result = 31 * result + classNames.hashCode();
130    //            result = 31 * result + methodClassAndSigs.hashCode();
131    //            return result;
132    //        }
133    
134    
135        /**
136         * Returns true if the two ThreadCheckDefinitionRecords are equal.
137         * @param o other object
138         * @return true if equal
139         */
140        public boolean equals(Object o) {
141            if (this == o) {
142                return true;
143            }
144            if (o == null || getClass() != o.getClass()) {
145                return false;
146            }
147    
148            ThreadCheckDefinitionRecord that = (ThreadCheckDefinitionRecord)o;
149    
150            if (!classNames.equals(that.classNames)) {
151                return false;
152            }
153            if (!invariant.equals(that.invariant)) {
154                return false;
155            }
156            if (!methodClassAndSigs.equals(that.methodClassAndSigs)) {
157                return false;
158            }
159    
160            return true;
161        }
162    
163        /**
164         * Return a hashcode for this ThreadCheckDefinitionRecord.
165         * @return hashcode
166         */
167        public int hashCode() {
168            int result;
169            result = invariant.hashCode();
170            result = 31 * result + classNames.hashCode();
171            result = 31 * result + methodClassAndSigs.hashCode();
172            return result;
173        }
174    
175        /**
176         * Returns a string representation of the object.
177         * @return a string representation of the object.
178         */
179        public String toString() {
180            StringBuilder sb = new StringBuilder();
181            sb.append("Invariant: ");
182            sb.append(invariant);
183            sb.append(XMLConfig.NL);
184            if (classNames.size()>0) {
185                sb.append("\tClasses: "+classNames.size());
186                for(String s: classNames) {
187                    sb.append("\t\t");
188                    sb.append(s);
189                    sb.append(XMLConfig.NL);
190                }
191            }
192            if (methodClassAndSigs.size()>0) {
193                sb.append("\tMethods: "+methodClassAndSigs.size());
194                for(String s: classNames) {
195                    sb.append("\t\t");
196                    sb.append(s);
197                    sb.append(XMLConfig.NL);
198                }
199            }
200            return super.toString();
201        }
202    }