1 package iotruntime.master;
4 import java.io.FileInputStream;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.util.Arrays;
9 import java.util.Collection;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Iterator;
14 import java.util.Properties;
17 import java.lang.reflect.*;
18 import java.util.regex.Matcher;
19 import java.util.regex.Pattern;
22 import org.objectweb.asm.AnnotationVisitor;
23 import org.objectweb.asm.Attribute;
24 import org.objectweb.asm.ClassReader;
25 import org.objectweb.asm.ClassWriter;
26 import org.objectweb.asm.ClassVisitor;
27 import org.objectweb.asm.FieldVisitor;
28 import org.objectweb.asm.MethodVisitor;
29 import org.objectweb.asm.Opcodes;
30 import org.objectweb.asm.signature.SignatureReader;
31 import org.objectweb.asm.signature.SignatureVisitor;
32 import org.objectweb.asm.TypePath;
35 import iotruntime.slave.IoTSet;
36 import iotruntime.slave.IoTRelation;
38 /** Class ClassRuntimeInstrumenterMaster helps instrument the bytecode.
39 * This class basically reads annotations @config in the code,
40 * allocates the right objects, and runs the function init in
41 * the instrumented program code.
43 * @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
47 public final class ClassRuntimeInstrumenterMaster extends ClassVisitor implements Opcodes {
50 * ClassRuntimeInstrumenterMaster class properties
52 * At most we will have 3 class types
53 * IoTSet<class_type> -> type 1: Set and type 2: class_type
54 * IoTRelation<class_type1, class_type2>
55 * -> type 1: IoTRelation, type 2: class_type1, type 3: class_type2
56 * Store class type for annotation processing in strClassType
58 private String[] strClassType;
59 private static int iCntClassType = 0;
60 private String strInstrumentedClassName;
61 private String strFieldName;
62 private HashMap<String,Object> hmObj;
63 private String strObjectID;
64 private boolean bVerbose;
67 * ClassRuntimeInstrumenterMaster class constants
69 private static final int INT_NUM_CLASS_TYPE = 3;
70 //private static final String STR_IOT_ANNOTATION_SIGNATURE = "Liotchecker/qual/config;";
71 private static final String STR_IOT_ANNOTATION_SIGNATURE = "Liotcode/annotation/config;";
72 private static final String STR_IOT_SET_SIGNATURE = "Liotruntime/slave/IoTSet;";
73 private static final String STR_IOT_RELATION_SIGNATURE = "Liotruntime/slave/IoTRelation;";
74 private static final String STR_IOT_CONSTRAINT_SIGNATURE = "Liotcode/annotation/constraint;";
75 private static final String STR_CONFIG_EXTENSION = ".config";
76 private static final String STR_CONFIG_FILE_PATH = "mysql/";
81 public ClassRuntimeInstrumenterMaster(final ClassVisitor cv, String strObjID, boolean _bVerbose) {
85 // Initialize strClassType
86 strClassType = new String[INT_NUM_CLASS_TYPE];
87 for(int i=0; i<INT_NUM_CLASS_TYPE; i++) {
88 strClassType[i] = new String();
90 strInstrumentedClassName = "";
92 hmObj = new HashMap<String,Object>();
93 strObjectID = strObjID;
98 * Make a visit to a class. This is the method called first.
101 public void visit(int version, int access, String name,
102 String signature, String superName, String[] interfaces) {
104 // Get the name of this instrumented class
105 strInstrumentedClassName = name;
107 super.visit(version, access, name, signature, superName, interfaces);
111 * Make a visit to a field.
114 public FieldVisitor visitField(int access, String name,
115 String desc, String signature, Object value) {
118 super.visitField(access, name, desc, signature, value);
120 if (signature != null) {
121 new SignatureReader(signature)
122 .accept(new SignatureRuntimeInstrumenter(strClassType));
125 return new FieldRuntimeInstrumenter(signature, desc);
129 * Visit a method when a method is encountered
132 public MethodVisitor visitMethod(int access, String name,
133 String desc, String signature, String[] exceptions) {
135 super.visitMethod(access, name, desc, signature, exceptions);
136 return new MethodRuntimeInstrumenter();
140 * A subclass that visits signature. This is called when traversing a class
141 * and a signature visit is needed.
143 private class SignatureRuntimeInstrumenter extends SignatureVisitor {
145 public SignatureRuntimeInstrumenter(String[] strCType) {
148 // Counter for extracting +class type
151 // Initializing input String array
152 for (int i=0; i<INT_NUM_CLASS_TYPE; i++) {
153 strClassType[i] = strCType[i];
158 public void visitClassType(final String name) {
160 strClassType[iCntClassType++] = name;
161 super.visitClassType(name);
166 * A helper function that returns class name from class type pattern
168 * e.g. get "ProximitySensor" from "iotcode/ProximitySensor"
169 * With this regex pattern,
170 * group(0) gives the entire input string, e.g. "iotcode/ProximitySensor"
171 * group(1) gives just the front string, e.g. "iotcode"
172 * group(2) gives just the slash, e.g. "/"
173 * group(3) gives just the back string, e.g. "ProximitySensor"
175 * @param strInput String to be matched by regex
178 public String getClassName(String strInput) {
180 Pattern pattern = Pattern.compile("(\\S+)(\\/)(\\S+)");
181 Matcher matcher = pattern.matcher(strInput);
182 if (matcher.find()) {
183 return matcher.group(3);
189 * A class that instruments instructions in method through visiting a method.
190 * Instruction and variable types can be extracted.
192 class FieldRuntimeInstrumenter extends FieldVisitor {
194 private String strFieldSignature;
195 private String strFieldDesc;
197 public FieldRuntimeInstrumenter(String strFSign, String strFDesc) {
200 strFieldSignature = strFSign;
201 strFieldDesc = strFDesc;
205 * This method visits annotation, so we can instrument @config here
208 * 1) Check whether it is IoTSet or IoTRelation declaration
209 * 2) Create a new Set class instrumenter
210 * strClassType[0] will contain "IoTSet" or "IoTRelation"
211 * strClassType[1] will contain the first specific class
212 * e.g. IoTSet<ProximitySensor> -> strClassType[1] == "ProximitySensor"
213 * strClassType[2] will contain the other specific class
214 * (doesn't apply to IoTSet)
215 * e.g. IoTRelation<ProximitySensor, LightBulb>
216 * -> strClassType[1] == "ProximitySensor"
217 * -> strClassType[2] == "LightBulb"
218 * 3) Instantiate field objects, e.g. IoTSet or IoTRelation class object
219 * 4) Instantiate a new object of the instrumented class, e.g. AcmeThermostat
220 * 5) Initialize the field of the instrumented class objects with actual field objects
221 * 6) Run the init() function of the instrumented class
224 * @param visible boolean
225 * @return AnnotationVisitor
228 * This method visits annotation that is meta-annotated as TYPE_USE, so we can instrument @config here
231 public AnnotationVisitor visitAnnotation(String desc,
234 RuntimeOutput.print("ClassRuntimeInstrumenterMaster@AnnotationVisitor: " + desc, bVerbose);
236 // Check annotation description @config
237 if(desc.equals(STR_IOT_ANNOTATION_SIGNATURE)) {
238 // Check if this is a Set class, then process it
239 if (strFieldDesc.equals(STR_IOT_SET_SIGNATURE)) {
240 RuntimeOutput.print("@config: IoTSet is detected!", bVerbose);
241 SetInstrumenter setInstrument = new
242 SetInstrumenter(getClassName(strClassType[1]),
243 STR_CONFIG_FILE_PATH + strFieldName + STR_CONFIG_EXTENSION, strObjectID, bVerbose);
245 hmObj.put(strFieldName, setInstrument);
246 // Check if this is a Relation class, then process it
247 } else if (strFieldDesc.equals(STR_IOT_RELATION_SIGNATURE)) {
248 RuntimeOutput.print("@config: IoTRelation is detected!", bVerbose);
249 RelationInstrumenter relInstrument = new
250 RelationInstrumenter(getClassName(strClassType[1]),
251 getClassName(strClassType[2]), STR_CONFIG_FILE_PATH +
252 strFieldName + STR_CONFIG_EXTENSION, bVerbose);
254 hmObj.put(strFieldName, relInstrument);
255 } else if (strFieldDesc.equals(STR_IOT_CONSTRAINT_SIGNATURE)) {
256 // TO DO: PROCESS THIS CONSTRAINT ANNOTATION
257 RuntimeOutput.print("ClassRuntimeInstrumenterMaster@AnnotationTypeVisitor: Constraint annotation detected!", bVerbose);
260 throw new Error("ClassRuntimeInstrumenterMaster@AnnotationTypeVisitor: " + strFieldDesc + " not recognized!");
263 return super.visitAnnotation(desc, visible);
268 * A subclass that instruments instructions in method through visiting a method.
269 * Instruction and variable types can be extracted.
271 protected class MethodRuntimeInstrumenter extends MethodVisitor {
273 public MethodRuntimeInstrumenter() {
280 * A method that returns HashMap hmObj
282 * @return HashMap<String,Object>
284 public HashMap<String,Object> getFieldObjects() {
289 public static void main(String[] args) {
292 // Instrumenting one file
293 FileInputStream is = new FileInputStream(args[0]);
295 ClassReader cr = new ClassReader(is);
296 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
297 ClassRuntimeInstrumenterMaster crim = new ClassRuntimeInstrumenterMaster(cw, "LB2", true);
300 // Get the object and the class names
301 HashMap<String,Object> hm = crim.getFieldObjects();
302 for(Map.Entry<String,Object> map : hm.entrySet()) {
303 System.out.println(map.getKey());
304 System.out.println(map.getValue().getClass().getName());
305 SetInstrumenter si = (SetInstrumenter) map.getValue();
306 System.out.println("Field values: " + Arrays.toString(si.fieldValues(0)));
307 System.out.println("Field classes: " + Arrays.toString(si.fieldClasses(0)));
308 System.out.println("Field object ID: " + si.fieldObjectID(0));
309 System.out.println("Field entry type: " + si.fieldEntryType("LB1"));
310 System.out.println("Field entry type: " + si.fieldEntryType("LB2"));
311 System.out.println("Number of rows: " + si.numberOfRows());
314 } catch (IOException ex) {
315 System.out.println("ClassRuntimeInstrumenterMaster@RunInstrumentation: IOException: "
317 ex.printStackTrace();