1/**
2 * $RCSfile$
3 * $Revision: 7071 $
4 * $Date: 2007-02-12 08:59:05 +0800 (Mon, 12 Feb 2007) $
5 *
6 * Copyright 2003-2007 Jive Software.
7 *
8 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *     http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21package org.jivesoftware.smackx.packet;
22
23import org.jivesoftware.smack.packet.IQ;
24import org.jivesoftware.smack.util.StringUtils;
25
26import java.util.Collection;
27import java.util.Collections;
28import java.util.Iterator;
29import java.util.List;
30import java.util.concurrent.CopyOnWriteArrayList;
31
32/**
33 * A DiscoverItems IQ packet, which is used by XMPP clients to request and receive items
34 * associated with XMPP entities.<p>
35 *
36 * The items could also be queried in order to discover if they contain items inside. Some items
37 * may be addressable by its JID and others may require to be addressed by a JID and a node name.
38 *
39 * @author Gaston Dombiak
40 */
41public class DiscoverItems extends IQ {
42
43    public static final String NAMESPACE = "http://jabber.org/protocol/disco#items";
44
45    private final List<Item> items = new CopyOnWriteArrayList<Item>();
46    private String node;
47
48    /**
49     * Adds a new item to the discovered information.
50     *
51     * @param item the discovered entity's item
52     */
53    public void addItem(Item item) {
54        synchronized (items) {
55            items.add(item);
56        }
57    }
58
59    /**
60     * Adds a collection of items to the discovered information. Does nothing if itemsToAdd is null
61     *
62     * @param itemsToAdd
63     */
64    public void addItems(Collection<Item> itemsToAdd) {
65        if (itemsToAdd == null) return;
66        for (Item i : itemsToAdd) {
67            addItem(i);
68        }
69    }
70
71    /**
72     * Returns the discovered items of the queried XMPP entity.
73     *
74     * @return an Iterator on the discovered entity's items
75     */
76    public Iterator<DiscoverItems.Item> getItems() {
77        synchronized (items) {
78            return Collections.unmodifiableList(items).iterator();
79        }
80    }
81
82    /**
83     * Returns the node attribute that supplements the 'jid' attribute. A node is merely
84     * something that is associated with a JID and for which the JID can provide information.<p>
85     *
86     * Node attributes SHOULD be used only when trying to provide or query information which
87     * is not directly addressable.
88     *
89     * @return the node attribute that supplements the 'jid' attribute
90     */
91    public String getNode() {
92        return node;
93    }
94
95    /**
96     * Sets the node attribute that supplements the 'jid' attribute. A node is merely
97     * something that is associated with a JID and for which the JID can provide information.<p>
98     *
99     * Node attributes SHOULD be used only when trying to provide or query information which
100     * is not directly addressable.
101     *
102     * @param node the node attribute that supplements the 'jid' attribute
103     */
104    public void setNode(String node) {
105        this.node = node;
106    }
107
108    public String getChildElementXML() {
109        StringBuilder buf = new StringBuilder();
110        buf.append("<query xmlns=\"" + NAMESPACE + "\"");
111        if (getNode() != null) {
112            buf.append(" node=\"");
113            buf.append(StringUtils.escapeForXML(getNode()));
114            buf.append("\"");
115        }
116        buf.append(">");
117        synchronized (items) {
118            for (Item item : items) {
119                buf.append(item.toXML());
120            }
121        }
122        buf.append("</query>");
123        return buf.toString();
124    }
125
126    /**
127     * An item is associated with an XMPP Entity, usually thought of a children of the parent
128     * entity and normally are addressable as a JID.<p>
129     *
130     * An item associated with an entity may not be addressable as a JID. In order to handle
131     * such items, Service Discovery uses an optional 'node' attribute that supplements the
132     * 'jid' attribute.
133     */
134    public static class Item {
135
136        /**
137         * Request to create or update the item.
138         */
139        public static final String UPDATE_ACTION = "update";
140
141        /**
142         * Request to remove the item.
143         */
144        public static final String REMOVE_ACTION = "remove";
145
146        private String entityID;
147        private String name;
148        private String node;
149        private String action;
150
151        /**
152         * Create a new Item associated with a given entity.
153         *
154         * @param entityID the id of the entity that contains the item
155         */
156        public Item(String entityID) {
157            this.entityID = entityID;
158        }
159
160        /**
161         * Returns the entity's ID.
162         *
163         * @return the entity's ID.
164         */
165        public String getEntityID() {
166            return entityID;
167        }
168
169        /**
170         * Returns the entity's name.
171         *
172         * @return the entity's name.
173         */
174        public String getName() {
175            return name;
176        }
177
178        /**
179         * Sets the entity's name.
180         *
181         * @param name the entity's name.
182         */
183        public void setName(String name) {
184            this.name = name;
185        }
186
187        /**
188         * Returns the node attribute that supplements the 'jid' attribute. A node is merely
189         * something that is associated with a JID and for which the JID can provide information.<p>
190         *
191         * Node attributes SHOULD be used only when trying to provide or query information which
192         * is not directly addressable.
193         *
194         * @return the node attribute that supplements the 'jid' attribute
195         */
196        public String getNode() {
197            return node;
198        }
199
200        /**
201         * Sets the node attribute that supplements the 'jid' attribute. A node is merely
202         * something that is associated with a JID and for which the JID can provide information.<p>
203         *
204         * Node attributes SHOULD be used only when trying to provide or query information which
205         * is not directly addressable.
206         *
207         * @param node the node attribute that supplements the 'jid' attribute
208         */
209        public void setNode(String node) {
210            this.node = node;
211        }
212
213        /**
214         * Returns the action that specifies the action being taken for this item. Possible action
215         * values are: "update" and "remove". Update should either create a new entry if the node
216         * and jid combination does not already exist, or simply update an existing entry. If
217         * "remove" is used as the action, the item should be removed from persistent storage.
218         *
219         * @return the action being taken for this item
220         */
221        public String getAction() {
222            return action;
223        }
224
225        /**
226         * Sets the action that specifies the action being taken for this item. Possible action
227         * values are: "update" and "remove". Update should either create a new entry if the node
228         * and jid combination does not already exist, or simply update an existing entry. If
229         * "remove" is used as the action, the item should be removed from persistent storage.
230         *
231         * @param action the action being taken for this item
232         */
233        public void setAction(String action) {
234            this.action = action;
235        }
236
237        public String toXML() {
238            StringBuilder buf = new StringBuilder();
239            buf.append("<item jid=\"").append(entityID).append("\"");
240            if (name != null) {
241                buf.append(" name=\"").append(StringUtils.escapeForXML(name)).append("\"");
242            }
243            if (node != null) {
244                buf.append(" node=\"").append(StringUtils.escapeForXML(node)).append("\"");
245            }
246            if (action != null) {
247                buf.append(" action=\"").append(StringUtils.escapeForXML(action)).append("\"");
248            }
249            buf.append("/>");
250            return buf.toString();
251        }
252    }
253}
254