1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.rop.annotation;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstString;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstType;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.MutabilityControl;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.ToHuman;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Collection;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Collections;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Iterator;
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.TreeMap;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * An annotation on an element of a class. Annotations have an
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * associated type and additionally consist of a set of (name, value)
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * pairs, where the names are unique.
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class Annotation extends MutabilityControl
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        implements Comparable<Annotation>, ToHuman {
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} type of the annotation */
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final CstType type;
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} the visibility of the annotation */
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final AnnotationVisibility visibility;
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} map from names to {@link NameValuePair} instances */
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final TreeMap<CstString, NameValuePair> elements;
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Construct an instance. It initially contains no elements.
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param type {@code non-null;} type of the annotation
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param visibility {@code non-null;} the visibility of the annotation
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Annotation(CstType type, AnnotationVisibility visibility) {
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (type == null) {
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("type == null");
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (visibility == null) {
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("visibility == null");
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.type = type;
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.visibility = visibility;
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.elements = new TreeMap<CstString, NameValuePair>();
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public boolean equals(Object other) {
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (! (other instanceof Annotation)) {
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return false;
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Annotation otherAnnotation = (Annotation) other;
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (! (type.equals(otherAnnotation.type)
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        && (visibility == otherAnnotation.visibility))) {
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return false;
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return elements.equals(otherAnnotation.elements);
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int hashCode() {
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int hash = type.hashCode();
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        hash = (hash * 31) + elements.hashCode();
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        hash = (hash * 31) + visibility.hashCode();
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return hash;
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int compareTo(Annotation other) {
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int result = type.compareTo(other.type);
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (result != 0) {
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return result;
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        result = visibility.compareTo(other.visibility);
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (result != 0) {
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return result;
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Iterator<NameValuePair> thisIter = elements.values().iterator();
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Iterator<NameValuePair> otherIter = other.elements.values().iterator();
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        while (thisIter.hasNext() && otherIter.hasNext()) {
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            NameValuePair thisOne = thisIter.next();
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            NameValuePair otherOne = otherIter.next();
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result = thisOne.compareTo(otherOne);
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (result != 0) {
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return result;
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (thisIter.hasNext()) {
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return 1;
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (otherIter.hasNext()) {
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return -1;
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return 0;
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String toString() {
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return toHuman();
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String toHuman() {
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StringBuilder sb = new StringBuilder();
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(visibility.toHuman());
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append("-annotation ");
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(type.toHuman());
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(" {");
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean first = true;
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (NameValuePair pair : elements.values()) {
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (first) {
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                first = false;
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append(", ");
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(pair.getName().toHuman());
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(": ");
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(pair.getValue().toHuman());
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append("}");
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return sb.toString();
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the type of this instance.
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the type
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public CstType getType() {
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return type;
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the visibility of this instance.
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the visibility
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public AnnotationVisibility getVisibility() {
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return visibility;
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Put an element into the set of (name, value) pairs for this instance.
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * If there is a preexisting element with the same name, it will be
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * replaced by this method.
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param pair {@code non-null;} the (name, value) pair to place into this instance
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void put(NameValuePair pair) {
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        throwIfImmutable();
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (pair == null) {
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("pair == null");
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        elements.put(pair.getName(), pair);
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Add an element to the set of (name, value) pairs for this instance.
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * It is an error to call this method if there is a preexisting element
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * with the same name.
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param pair {@code non-null;} the (name, value) pair to add to this instance
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void add(NameValuePair pair) {
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        throwIfImmutable();
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (pair == null) {
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("pair == null");
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        CstString name = pair.getName();
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (elements.get(name) != null) {
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("name already added: " + name);
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        elements.put(name, pair);
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the set of name-value pairs contained in this instance. The
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * result is always unmodifiable.
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the set of name-value pairs
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Collection<NameValuePair> getNameValuePairs() {
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return Collections.unmodifiableCollection(elements.values());
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
225