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