001package serp.bytecode;
002
003import java.io.*;
004import java.util.*;
005
006import serp.bytecode.visitor.*;
007
008/**
009 * Java annotation data.
010 *
011 * @author Abe White
012 */
013public 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}