001    package serp.bytecode;
002    
003    import java.io.*;
004    import java.util.*;
005    
006    import serp.bytecode.visitor.*;
007    
008    /**
009     * Java annotation data.
010     *
011     * @author Abe White
012     */
013    public class Annotations extends Attribute {
014        private final List _annotations = new ArrayList();
015    
016        Annotations(int nameIndex, Attributes owner) {
017            super(nameIndex, owner);
018        }
019    
020        /**
021         * Whether these annotations are runtime-visible.
022         */
023        public boolean isRuntime() {
024            return getName().equals(Constants.ATTR_RUNTIME_ANNOTATIONS);
025        }
026    
027        /**
028         * All declared annotations.
029         */
030        public Annotation[] getAnnotations() {
031            return (Annotation[]) _annotations.toArray
032                (new Annotation[_annotations.size()]);
033        }
034    
035        /**
036         * Set the annotations.  This method is useful when
037         * importing annotations from another instance.
038         */
039        public void setAnnotations(Annotation[] annos) {
040            clear();
041            if (annos != null)
042                for (int i = 0; i < annos.length; i++)
043                    addAnnotation(annos[i]);
044        }
045    
046        /**
047         * Return the annotation of the given type, or null if none.
048         */
049        public Annotation getAnnotation(Class type) {
050            return (type == null) ? null : getAnnotation(type.getName());
051        }
052    
053        /**
054         * Return the annotation of the given type, or null if none.
055         */
056        public Annotation getAnnotation(BCClass type) {
057            return (type == null) ? null : getAnnotation(type.getName());
058        }
059    
060        /**
061         * Return the annotation of the given type, or null if none.
062         */
063        public Annotation getAnnotation(String type) {
064            Annotation anno;
065            for (int i = 0; i < _annotations.size(); i++) {
066                anno = (Annotation) _annotations.get(i);
067                if (anno.getTypeName().equals(type))
068                    return anno;
069            }
070            return null;
071        }
072    
073        /**
074         * Import an annotation from another instance.
075         *
076         * @return the newly added annotation
077         */
078        public Annotation addAnnotation(Annotation an) {
079            Annotation anno = addAnnotation(an.getTypeName());
080            anno.setProperties(an.getProperties());
081            return anno;
082        }
083    
084        /**
085         * Add a new annotation.
086         */
087        public Annotation addAnnotation(Class type) {
088            return addAnnotation(type.getName());
089        }
090    
091        /**
092         * Add a new annotation.
093         */
094        public Annotation addAnnotation(BCClass type) {
095            return addAnnotation(type.getName());
096        }
097    
098        /**
099         * Add a new annotation.
100         */
101        public Annotation addAnnotation(String type) {
102            Annotation anno = new Annotation(this);
103            anno.setType(type);
104            _annotations.add(anno);
105            return anno;
106        }
107    
108        /**
109         * Remove all annotations.
110         */
111        public void clear() {
112            for (int i = 0; i < _annotations.size(); i++)
113                ((Annotation) _annotations.get(i)).invalidate();
114            _annotations.clear();
115        }
116    
117        /**
118         * Remove the given annotation.
119         *
120         * @return true if an annotation was removed, false otherwise
121         */
122        public boolean removeAnnotation(Annotation anno) {
123            return anno != null && removeAnnotation(anno.getTypeName());
124        }
125    
126        /**
127         * Remove the annotation of the given type.   
128         *
129         * @return true if an annotation was removed, false otherwise
130         */
131        public boolean removeAnnotation(Class type) {
132            return type != null && removeAnnotation(type.getName());
133        }
134    
135        /**
136         * Remove the annotation of the given type.   
137         *
138         * @return true if an annotation was removed, false otherwise
139         */
140        public boolean removeAnnotation(BCClass type) {
141            return type != null && removeAnnotation(type.getName());
142        }
143    
144        /**
145         * Remove the annotation of the given type.   
146         *
147         * @return true if an annotation was removed, false otherwise
148         */
149        public boolean removeAnnotation(String type) {
150            if (type == null)
151                return false;
152            Annotation anno;
153            for (int i = 0; i < _annotations.size(); i++) {
154                anno = (Annotation) _annotations.get(i);
155                if (anno.getTypeName().equals(type)) {
156                    anno.invalidate();
157                    _annotations.remove(i);
158                    return true;
159                }
160            }
161            return false;
162        }
163    
164        int getLength() {
165            int len = 2;
166            for (int i = 0; i < _annotations.size(); i++)
167                len += ((Annotation) _annotations.get(i)).getLength();
168            return len;
169        }
170    
171        void read(Attribute other) {
172            setAnnotations(((Annotations) other).getAnnotations());
173        }
174    
175        void read(DataInput in, int length) throws IOException {
176            _annotations.clear();
177            int annos = in.readUnsignedShort();
178            Annotation anno;
179            for (int i = 0; i < annos; i++) {
180                anno = new Annotation(this);
181                anno.read(in);
182                _annotations.add(anno);
183            }
184        }
185    
186        void write(DataOutput out, int length) throws IOException {
187            out.writeShort(_annotations.size());
188            for (int i = 0; i < _annotations.size(); i++)
189                ((Annotation) _annotations.get(i)).write(out);
190        }
191    
192        public void acceptVisit(BCVisitor visit) {
193            visit.enterAnnotations(this);
194            for (int i = 0; i < _annotations.size(); i++)
195                ((Annotation) _annotations.get(i)).acceptVisit(visit);
196            visit.exitAnnotations(this);
197        }
198    }