1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $RCSfile$
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Revision$
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Date$
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2003-2007 Jive Software.
7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License.
10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at
11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *     http://www.apache.org/licenses/LICENSE-2.0
13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software
15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS,
16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and
18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License.
19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smackx.packet;
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.IQ;
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.util.StringUtils;
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Collection;
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Collections;
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Iterator;
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.LinkedList;
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.List;
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.concurrent.CopyOnWriteArrayList;
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * A DiscoverInfo IQ packet, which is used by XMPP clients to request and receive information
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * to/from other XMPP entities.<p>
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * The received information may contain one or more identities of the requested XMPP entity, and
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * a list of supported features by the requested XMPP entity.
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Gaston Dombiak
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class DiscoverInfo extends IQ {
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static final String NAMESPACE = "http://jabber.org/protocol/disco#info";
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private final List<Feature> features = new CopyOnWriteArrayList<Feature>();
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private final List<Identity> identities = new CopyOnWriteArrayList<Identity>();
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String node;
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public DiscoverInfo() {
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        super();
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Copy constructor
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param d
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public DiscoverInfo(DiscoverInfo d) {
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        super(d);
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Set node
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setNode(d.getNode());
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Copy features
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (d.features) {
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            for (Feature f : d.features) {
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                addFeature(f);
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Copy identities
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (d.identities) {
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            for (Identity i : d.identities) {
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                addIdentity(i);
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Adds a new feature to the discovered information.
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param feature the discovered feature
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void addFeature(String feature) {
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        addFeature(new Feature(feature));
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Adds a collection of features to the packet. Does noting if featuresToAdd is null.
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param featuresToAdd
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void addFeatures(Collection<String> featuresToAdd) {
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (featuresToAdd == null) return;
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (String feature : featuresToAdd) {
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            addFeature(feature);
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private void addFeature(Feature feature) {
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (features) {
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            features.add(feature);
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the discovered features of an XMPP entity.
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return an Iterator on the discovered features of an XMPP entity
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Iterator<Feature> getFeatures() {
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (features) {
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return Collections.unmodifiableList(features).iterator();
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Adds a new identity of the requested entity to the discovered information.
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param identity the discovered entity's identity
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void addIdentity(Identity identity) {
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (identities) {
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            identities.add(identity);
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Adds identities to the DiscoverInfo stanza
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param identitiesToAdd
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void addIdentities(Collection<Identity> identitiesToAdd) {
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (identitiesToAdd == null) return;
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (identities) {
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            identities.addAll(identitiesToAdd);
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the discovered identities of an XMPP entity.
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return an Iterator on the discoveted identities
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Iterator<Identity> getIdentities() {
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (identities) {
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return Collections.unmodifiableList(identities).iterator();
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the node attribute that supplements the 'jid' attribute. A node is merely
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * something that is associated with a JID and for which the JID can provide information.<p>
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Node attributes SHOULD be used only when trying to provide or query information which
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * is not directly addressable.
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the node attribute that supplements the 'jid' attribute
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getNode() {
162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return node;
163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Sets the node attribute that supplements the 'jid' attribute. A node is merely
167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * something that is associated with a JID and for which the JID can provide information.<p>
168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Node attributes SHOULD be used only when trying to provide or query information which
170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * is not directly addressable.
171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param node the node attribute that supplements the 'jid' attribute
173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setNode(String node) {
175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.node = node;
176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns true if the specified feature is part of the discovered information.
180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param feature the feature to check
182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return true if the requestes feature has been discovered
183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean containsFeature(String feature) {
185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (Iterator<Feature> it = getFeatures(); it.hasNext();) {
186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (feature.equals(it.next().getVar()))
187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return true;
188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return false;
190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getChildElementXML() {
193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        StringBuilder buf = new StringBuilder();
194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        buf.append("<query xmlns=\"" + NAMESPACE + "\"");
195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (getNode() != null) {
196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append(" node=\"");
197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append(StringUtils.escapeForXML(getNode()));
198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append("\"");
199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        buf.append(">");
201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (identities) {
202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            for (Identity identity : identities) {
203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                buf.append(identity.toXML());
204d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (features) {
207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            for (Feature feature : features) {
208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                buf.append(feature.toXML());
209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
211d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Add packet extensions, if any are defined.
212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        buf.append(getExtensionsXML());
213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        buf.append("</query>");
214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return buf.toString();
215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
217d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
218d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Test if a DiscoverInfo response contains duplicate identities.
219d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
220d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return true if duplicate identities where found, otherwise false
221d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
222d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean containsDuplicateIdentities() {
223d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        List<Identity> checkedIdentities = new LinkedList<Identity>();
224d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (Identity i : identities) {
225d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            for (Identity i2 : checkedIdentities) {
226d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (i.equals(i2))
227d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    return true;
228d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
229d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            checkedIdentities.add(i);
230d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
231d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return false;
232d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
233d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
234d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
235d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Test if a DiscoverInfo response contains duplicate features.
236d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
237d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return true if duplicate identities where found, otherwise false
238d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
239d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean containsDuplicateFeatures() {
240d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        List<Feature> checkedFeatures = new LinkedList<Feature>();
241d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (Feature f : features) {
242d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            for (Feature f2 : checkedFeatures) {
243d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (f.equals(f2))
244d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    return true;
245d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
246d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            checkedFeatures.add(f);
247d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
248d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return false;
249d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
250d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
251d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
252d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Represents the identity of a given XMPP entity. An entity may have many identities but all
253d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * the identities SHOULD have the same name.<p>
254d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
255d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a>
256d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * in order to get the official registry of values for the <i>category</i> and <i>type</i>
257d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * attributes.
258d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
259d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
260d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static class Identity implements Comparable<Identity> {
261d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
262d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private String category;
263d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private String name;
264d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private String type;
265d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private String lang; // 'xml:lang;
266d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
267d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
268d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Creates a new identity for an XMPP entity.
269d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
270d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @param category the entity's category.
271d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @param name the entity's name.
272d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @deprecated As per the spec, the type field is mandatory and the 3 argument constructor should be used instead.
273d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
274d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public Identity(String category, String name) {
275d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.category = category;
276d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.name = name;
277d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
278d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
279d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
280d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Creates a new identity for an XMPP entity.
281d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * 'category' and 'type' are required by
282d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * <a href="http://xmpp.org/extensions/xep-0030.html#schemas">XEP-30 XML Schemas</a>
283d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
284d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @param category the entity's category (required as per XEP-30).
285d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @param name the entity's name.
286d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @param type the entity's type (required as per XEP-30).
287d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
288d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public Identity(String category, String name, String type) {
289d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if ((category == null) || (type == null))
290d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                throw new IllegalArgumentException("category and type cannot be null");
291d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
292d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.category = category;
293d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.name = name;
294d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.type = type;
295d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
296d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
297d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
298d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Returns the entity's category. To get the official registry of values for the
299d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * 'category' attribute refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a>
300d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
301d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @return the entity's category.
302d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
303d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String getCategory() {
304d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return category;
305d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
306d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
307d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
308d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Returns the identity's name.
309d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
310d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @return the identity's name.
311d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
312d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String getName() {
313d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return name;
314d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
315d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
316d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
317d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Returns the entity's type. To get the official registry of values for the
318d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * 'type' attribute refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a>
319d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
320d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @return the entity's type.
321d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
322d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String getType() {
323d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return type;
324d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
325d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
326d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
327d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Sets the entity's type. To get the official registry of values for the
328d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * 'type' attribute refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a>
329d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
330d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @param type the identity's type.
331d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @deprecated As per the spec, this field is mandatory and the 3 argument constructor should be used instead.
332d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
333d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public void setType(String type) {
334d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.type = type;
335d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
336d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
337d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
338d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Sets the natural language (xml:lang) for this identity (optional)
339d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
340d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @param lang the xml:lang of this Identity
341d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
342d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public void setLanguage(String lang) {
343d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.lang = lang;
344d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
345d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
346d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
347d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Returns the identities natural language if one is set
348d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
349d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @return the value of xml:lang of this Identity
350d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
351d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String getLanguage() {
352d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return lang;
353d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
354d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
355d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String toXML() {
356d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            StringBuilder buf = new StringBuilder();
357d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append("<identity");
358d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Check if this packet has 'lang' set and maybe append it to the resulting string
359d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (lang != null)
360d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                buf.append(" xml:lang=\"").append(StringUtils.escapeForXML(lang)).append("\"");
361d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Category must always be set
362d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append(" category=\"").append(StringUtils.escapeForXML(category)).append("\"");
363d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Name must always be set
364d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append(" name=\"").append(StringUtils.escapeForXML(name)).append("\"");
365d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Check if this packet has 'type' set and maybe append it to the resulting string
366d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (type != null) {
367d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                buf.append(" type=\"").append(StringUtils.escapeForXML(type)).append("\"");
368d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
369d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append("/>");
370d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return buf.toString();
371d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
372d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
373d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
374d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Check equality for Identity  for category, type, lang and name
375d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * in that order as defined by
376d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * <a href="http://xmpp.org/extensions/xep-0115.html#ver-proc">XEP-0015 5.4 Processing Method (Step 3.3)</a>
377d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
378d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
379d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public boolean equals(Object obj) {
380d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (obj == null)
381d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
382d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (obj == this)
383d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return true;
384d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (obj.getClass() != getClass())
385d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
386d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
387d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            DiscoverInfo.Identity other = (DiscoverInfo.Identity) obj;
388d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (!this.category.equals(other.category))
389d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
390d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
391d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            String otherLang = other.lang == null ? "" : other.lang;
392d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            String thisLang = lang == null ? "" : lang;
393d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (!otherLang.equals(thisLang))
394d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
395d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
396d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // This safeguard can be removed once the deprecated constructor is removed.
397d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            String otherType = other.type == null ? "" : other.type;
398d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            String thisType = type == null ? "" : type;
399d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (!otherType.equals(thisType))
400d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
401d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
402d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            String otherName = other.name == null ? "" : other.name;
403d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            String thisName = name == null ? "" : other.name;
404d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (!thisName.equals(otherName))
405d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
406d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
407d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return true;
408d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
409d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
410d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        @Override
411d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public int hashCode() {
412d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            int result = 1;
413d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            result = 37 * result + category.hashCode();
414d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            result = 37 * result + (lang == null ? 0 : lang.hashCode());
415d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            result = 37 * result + (type == null ? 0 : type.hashCode());
416d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            result = 37 * result + (name == null ? 0 : name.hashCode());
417d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return result;
418d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
419d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
420d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
421d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Compares this identity with another one. The comparison order is:
422d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Category, Type, Lang. If all three are identical the other Identity is considered equal.
423d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Name is not used for comparision, as defined by XEP-0115
424d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
425d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @param obj
426d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @return
427d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
428d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public int compareTo(DiscoverInfo.Identity other) {
429d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            String otherLang = other.lang == null ? "" : other.lang;
430d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            String thisLang = lang == null ? "" : lang;
431d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
432d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // This can be removed once the deprecated constructor is removed.
433d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            String otherType = other.type == null ? "" : other.type;
434d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            String thisType = type == null ? "" : type;
435d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
436d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (category.equals(other.category)) {
437d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (thisType.equals(otherType)) {
438d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    if (thisLang.equals(otherLang)) {
439d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // Don't compare on name, XEP-30 says that name SHOULD
440d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // be equals for all identities of an entity
441d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        return 0;
442d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    } else {
443d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        return thisLang.compareTo(otherLang);
444d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
445d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                } else {
446d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    return thisType.compareTo(otherType);
447d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
448d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            } else {
449d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return category.compareTo(other.category);
450d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
451d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
452d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
453d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
454d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
455d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Represents the features offered by the item. This information helps requestors determine
456d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * what actions are possible with regard to this item (registration, search, join, etc.)
457d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * as well as specific feature types of interest, if any (e.g., for the purpose of feature
458d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * negotiation).
459d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
460d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static class Feature {
461d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
462d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private String variable;
463d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
464d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
465d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Creates a new feature offered by an XMPP entity or item.
466d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
467d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @param variable the feature's variable.
468d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
469d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public Feature(String variable) {
470d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (variable == null)
471d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                throw new IllegalArgumentException("variable cannot be null");
472d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.variable = variable;
473d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
474d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
475d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
476d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Returns the feature's variable.
477d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         *
478d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * @return the feature's variable.
479d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
480d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String getVar() {
481d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return variable;
482d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
483d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
484d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String toXML() {
485d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            StringBuilder buf = new StringBuilder();
486d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            buf.append("<feature var=\"").append(StringUtils.escapeForXML(variable)).append("\"/>");
487d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return buf.toString();
488d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
489d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
490d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public boolean equals(Object obj) {
491d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (obj == null)
492d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
493d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (obj == this)
494d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return true;
495d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (obj.getClass() != getClass())
496d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
497d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
498d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            DiscoverInfo.Feature other = (DiscoverInfo.Feature) obj;
499d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return variable.equals(other.variable);
500d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
501d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
502d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        @Override
503d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public int hashCode() {
504d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return 37 * variable.hashCode();
505d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
506d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
507d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
508