001    package edu.rice.cs.cunit.classFile.attributes;
002    
003    import edu.rice.cs.cunit.classFile.ClassFile;
004    import edu.rice.cs.cunit.classFile.attributes.visitors.IAttributeVisitor;
005    import edu.rice.cs.cunit.classFile.code.instructions.LineNumberTable;
006    import edu.rice.cs.cunit.classFile.constantPool.APoolInfo;
007    import edu.rice.cs.cunit.classFile.constantPool.ASCIIPoolInfo;
008    import edu.rice.cs.cunit.classFile.constantPool.AUTFPoolInfo;
009    import edu.rice.cs.cunit.classFile.constantPool.ConstantPool;
010    import edu.rice.cs.cunit.classFile.constantPool.visitors.CheckUTFVisitor;
011    import edu.rice.cs.cunit.instrumentors.IInstrumentationStrategy;
012    
013    import java.io.ByteArrayOutputStream;
014    import java.util.List;
015    
016    /**
017     * Represents the Instrumentation attribute in a class file.
018     *
019     * @author Mathias Ricken
020     */
021    public class InstrumentationAttributeInfo extends AAttributeInfo {
022        /**
023         * Constructor.
024         *
025         * @param name attribute name
026         * @param data attribute data
027         * @param cp   constant pool
028         *
029         * @throws ClassFormatError
030         */
031        public InstrumentationAttributeInfo(AUTFPoolInfo name, byte[] data, ConstantPool cp) throws ClassFormatError {
032            super(name, data, cp);
033        }
034    
035        /**
036         * Return an array of instrumentator class names.
037         *
038         * @return array of instrumentator class names
039         *
040         * @throws ClassFormatError
041         */
042        public String[] getInstrumentatorClassNames() throws ClassFormatError {
043            String s = new String(_data);
044            return s.split(";");
045        }
046    
047        /**
048         * Return the instrumentator class names as string.
049         *
050         * @return string with instrumentator class names
051         *
052         * @throws ClassFormatError
053         */
054        public String getInstrumentatorClassNameString() throws ClassFormatError {
055            return new String(_data);
056        }
057    
058        /**
059         * Set the source file name information.
060         *
061         * @param classNames constant pool
062         */
063        public void setInstrumentatorClassNames(String[] classNames) {
064            StringBuilder sb = new StringBuilder();
065            for(String s: classNames) {
066                sb.append(';');
067                sb.append(s);
068            }
069            String s = sb.toString();
070            _data = new byte[s.length()-1];
071            System.arraycopy(s.toCharArray(), 1, _data, 0, s.length()-1);
072        }
073    
074        /**
075         * Execute a visitor on this attribute.
076         *
077         * @param visitor visitor
078         * @param param   visitor-specific parameter
079         *
080         * @return visitor-specific return value
081         */
082        public <R, D> R execute(IAttributeVisitor<R, D> visitor, D param) {
083            return visitor.instrumentationCase(this, param);
084        }
085    
086        /**
087         * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them.
088         *
089         * @param startPC program counter to start at
090         * @param deltaPC change in program counter values
091         */
092        public void adjustPC(int startPC, int deltaPC) {
093            // nothing to do
094        }
095    
096        /**
097         * Translate the program counter values contained in this attribute from an old line number table to a new one.
098         *
099         * @param index      critical point (insertion or deletion point)
100         * @param deltaIndex delta value to add to all old line numbers greater than the critical point
101         * @param oldLnt     old line number table
102         * @param newLnt     new line number table
103         */
104        public void translatePC(int index, int deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt) {
105            // nothing to do
106        }
107    
108        /**
109         * Creates and returns a copy of this object.
110         */
111        public Object clone() throws CloneNotSupportedException {
112            return super.clone();
113        }
114    
115        /**
116         * Return a human-readable version of this attribute.
117         *
118         * @return string
119         */
120        public String toString() {
121            return "Instrumentors  = "+getInstrumentatorClassNameString();
122        }
123    
124        /**
125         * Name of this attribute.
126         */
127        public static final String NAME = "edu.rice.cs.cunit.Instrumentation";
128    
129        /**
130         * Add the Instrumentation attribute with the given instrumentor class name string to the class file.
131         * @param cf class file
132         * @param s names of instrumentor classes, separated by ';'
133         */
134        public static void addInstrumentationAttributeInfo(ClassFile cf, String s) {
135            ByteArrayOutputStream baos = new ByteArrayOutputStream();
136            for(char ch: s.toCharArray()) {
137                baos.write((int)ch);
138            }
139    
140            // add a new name for the attribute
141            int[] l;
142    
143            AUTFPoolInfo attributeName = new ASCIIPoolInfo(NAME, cf.getConstantPool());
144            l = cf.addConstantPoolItems(new APoolInfo[]{attributeName});
145            attributeName = cf.getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null);
146            cf.addAttribute(new InstrumentationAttributeInfo(attributeName, baos.toByteArray(), cf.getConstantPool()));
147        }
148    
149        /**
150         * Add the Instrumentation attribute with the given list of instrumentors to the class file.
151         * @param cf class file
152         * @param itors list of instrumentors
153         */
154        public static void addInstrumentationAttributeInfo(ClassFile cf, List<IInstrumentationStrategy> itors) {
155            StringBuilder sb = new StringBuilder();
156            for(IInstrumentationStrategy itor : itors) {
157                sb.append(';');
158                sb.append(itor.getClass().getName());
159            }
160            String s = sb.toString();
161            if (s.length()>0) {
162                s = s.substring(1);
163            }
164            addInstrumentationAttributeInfo(cf, s);
165        }
166    
167        /**
168         * Returns the name of the attribute as it appears in the class file.
169         *
170         * @return name of the attribute.
171         */
172        public static String getAttributeName() {
173            return NAME;
174        }
175    }