001/** 002 * 003 * Copyright the original author or authors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.pubsub; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.List; 022 023import org.jivesoftware.smack.SmackException.NoResponseException; 024import org.jivesoftware.smack.SmackException.NotConnectedException; 025import org.jivesoftware.smack.XMPPException.XMPPErrorException; 026import org.jivesoftware.smack.packet.ExtensionElement; 027import org.jivesoftware.smack.packet.IQ.Type; 028 029import org.jivesoftware.smackx.disco.packet.DiscoverItems; 030import org.jivesoftware.smackx.pubsub.packet.PubSub; 031 032/** 033 * The main class for the majority of PubSub functionality. In general 034 * almost all PubSub capabilities are related to the concept of a node. 035 * All items are published to a node, and typically subscribed to by other 036 * users. These users then retrieve events based on this subscription. 037 * 038 * @author Robin Collier 039 */ 040public class LeafNode extends Node { 041 LeafNode(PubSubManager pubSubManager, String nodeId) { 042 super(pubSubManager, nodeId); 043 } 044 045 /** 046 * Get information on the items in the node in standard 047 * {@link DiscoverItems} format. 048 * 049 * @return The item details in {@link DiscoverItems} format 050 * @throws XMPPErrorException 051 * @throws NoResponseException if there was no response from the server. 052 * @throws NotConnectedException 053 * @throws InterruptedException 054 */ 055 public DiscoverItems discoverItems() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 056 DiscoverItems items = new DiscoverItems(); 057 items.setTo(pubSubManager.getServiceJid()); 058 items.setNode(getId()); 059 return pubSubManager.getConnection().createStanzaCollectorAndSend(items).nextResultOrThrow(); 060 } 061 062 /** 063 * Get the current items stored in the node. 064 * 065 * @param <T> type of the items. 066 * @return List of {@link Item} in the node 067 * @throws XMPPErrorException 068 * @throws NoResponseException if there was no response from the server. 069 * @throws NotConnectedException 070 * @throws InterruptedException 071 */ 072 public <T extends Item> List<T> getItems() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 073 return getItems((List<ExtensionElement>) null, null); 074 } 075 076 /** 077 * Get the current items stored in the node based 078 * on the subscription associated with the provided 079 * subscription id. 080 * 081 * @param subscriptionId - The subscription id for the 082 * associated subscription. 083 * @param <T> type of the items. 084 * 085 * @return List of {@link Item} in the node 086 * @throws XMPPErrorException 087 * @throws NoResponseException if there was no response from the server. 088 * @throws NotConnectedException 089 * @throws InterruptedException 090 */ 091 public <T extends Item> List<T> getItems(String subscriptionId) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 092 PubSub request = createPubsubPacket(Type.get, new GetItemsRequest(getId(), subscriptionId)); 093 return getItems(request); 094 } 095 096 /** 097 * Get the items specified from the node. This would typically be 098 * used when the server does not return the payload due to size 099 * constraints. The user would be required to retrieve the payload 100 * after the items have been retrieved via {@link #getItems()} or an 101 * event, that did not include the payload. 102 * 103 * @param ids Item ids of the items to retrieve 104 * @param <T> type of the items. 105 * 106 * @return The list of {@link Item} with payload 107 * @throws XMPPErrorException 108 * @throws NoResponseException if there was no response from the server. 109 * @throws NotConnectedException 110 * @throws InterruptedException 111 */ 112 public <T extends Item> List<T> getItems(Collection<String> ids) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 113 List<Item> itemList = new ArrayList<>(ids.size()); 114 115 for (String id : ids) { 116 itemList.add(new Item(id)); 117 } 118 PubSub request = createPubsubPacket(Type.get, new ItemsExtension(ItemsExtension.ItemsElementType.items, getId(), itemList)); 119 return getItems(request); 120 } 121 122 /** 123 * Get items persisted on the node, limited to the specified number. 124 * 125 * @param maxItems Maximum number of items to return 126 * @param <T> type of the items. 127 * 128 * @return List of {@link Item} 129 * @throws XMPPErrorException 130 * @throws NoResponseException if there was no response from the server. 131 * @throws NotConnectedException 132 * @throws InterruptedException 133 */ 134 public <T extends Item> List<T> getItems(int maxItems) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 135 PubSub request = createPubsubPacket(Type.get, new GetItemsRequest(getId(), maxItems)); 136 return getItems(request); 137 } 138 139 /** 140 * Get items persisted on the node, limited to the specified number 141 * based on the subscription associated with the provided subscriptionId. 142 * 143 * @param maxItems Maximum number of items to return 144 * @param subscriptionId The subscription which the retrieval is based 145 * on. 146 * 147 * @return List of {@link Item} 148 * @param <T> type of the items. 149 * 150 * @throws XMPPErrorException 151 * @throws NoResponseException if there was no response from the server. 152 * @throws NotConnectedException 153 * @throws InterruptedException 154 */ 155 public <T extends Item> List<T> getItems(int maxItems, String subscriptionId) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 156 PubSub request = createPubsubPacket(Type.get, new GetItemsRequest(getId(), subscriptionId, maxItems)); 157 return getItems(request); 158 } 159 160 /** 161 * Get items persisted on the node. 162 * <p> 163 * {@code additionalExtensions} can be used e.g. to add a "Result Set Management" extension. 164 * {@code returnedExtensions} will be filled with the stanza extensions found in the answer. 165 * </p> 166 * 167 * @param additionalExtensions additional {@code PacketExtensions} to be added to the request. 168 * This is an optional argument, if provided as null no extensions will be added. 169 * @param returnedExtensions a collection that will be filled with the returned packet 170 * extensions. This is an optional argument, if provided as null it won't be populated. 171 * @param <T> type of the items. 172 * 173 * @return List of {@link Item} 174 * @throws NoResponseException 175 * @throws XMPPErrorException 176 * @throws NotConnectedException 177 * @throws InterruptedException 178 */ 179 public <T extends Item> List<T> getItems(List<ExtensionElement> additionalExtensions, 180 List<ExtensionElement> returnedExtensions) throws NoResponseException, 181 XMPPErrorException, NotConnectedException, InterruptedException { 182 PubSub request = createPubsubPacket(Type.get, new GetItemsRequest(getId())); 183 request.addExtensions(additionalExtensions); 184 return getItems(request, returnedExtensions); 185 } 186 187 private <T extends Item> List<T> getItems(PubSub request) throws NoResponseException, 188 XMPPErrorException, NotConnectedException, InterruptedException { 189 return getItems(request, null); 190 } 191 192 @SuppressWarnings("unchecked") 193 private <T extends Item> List<T> getItems(PubSub request, 194 List<ExtensionElement> returnedExtensions) throws NoResponseException, 195 XMPPErrorException, NotConnectedException, InterruptedException { 196 PubSub result = pubSubManager.getConnection().createStanzaCollectorAndSend(request).nextResultOrThrow(); 197 ItemsExtension itemsElem = result.getExtension(PubSubElementType.ITEMS); 198 if (returnedExtensions != null) { 199 returnedExtensions.addAll(result.getExtensions()); 200 } 201 return (List<T>) itemsElem.getItems(); 202 } 203 204 /** 205 * Publishes an event to the node. This is an empty event 206 * with no item. 207 * 208 * This is only acceptable for nodes with {@link ConfigureForm#isPersistItems()}=false 209 * and {@link ConfigureForm#isDeliverPayloads()}=false. 210 * 211 * @throws NotConnectedException 212 * @throws InterruptedException 213 * @throws XMPPErrorException 214 * @throws NoResponseException 215 * @deprecated use {@link #publish()} instead. 216 */ 217 @Deprecated 218 public void send() throws NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException { 219 publish(); 220 } 221 222 /** 223 * Publishes an event to the node. This is a simple item 224 * with no payload. 225 * 226 * If the id is null, an empty item (one without an id) will be sent. 227 * Please note that this is not the same as {@link #send()}, which 228 * publishes an event with NO item. 229 * 230 * @param item - The item being sent 231 * @param <T> type of the items. 232 * 233 * @throws NotConnectedException 234 * @throws InterruptedException 235 * @throws XMPPErrorException 236 * @throws NoResponseException 237 * @deprecated use {@link #publish(Item)} instead. 238 */ 239 @SuppressWarnings("unchecked") 240 @Deprecated 241 public <T extends Item> void send(T item) throws NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException { 242 publish(item); 243 } 244 245 /** 246 * Publishes multiple events to the node. Same rules apply as in {@link #publish(Item)}. 247 * 248 * In addition, if {@link ConfigureForm#isPersistItems()}=false, only the last item in the input 249 * list will get stored on the node, assuming it stores the last sent item. 250 * 251 * @param items - The collection of items being sent 252 * @param <T> type of the items. 253 * 254 * @throws NotConnectedException 255 * @throws InterruptedException 256 * @throws XMPPErrorException 257 * @throws NoResponseException 258 * @deprecated use {@link #publish(Collection)} instead. 259 */ 260 @Deprecated 261 public <T extends Item> void send(Collection<T> items) throws NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException { 262 publish(items); 263 } 264 265 /** 266 * Publishes an event to the node. This is an empty event 267 * with no item. 268 * 269 * This is only acceptable for nodes with {@link ConfigureForm#isPersistItems()}=false 270 * and {@link ConfigureForm#isDeliverPayloads()}=false. 271 * 272 * @throws XMPPErrorException 273 * @throws NoResponseException 274 * @throws NotConnectedException 275 * @throws InterruptedException 276 * 277 */ 278 public void publish() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 279 PubSub packet = createPubsubPacket(Type.set, new NodeExtension(PubSubElementType.PUBLISH, getId())); 280 281 pubSubManager.getConnection().createStanzaCollectorAndSend(packet).nextResultOrThrow(); 282 } 283 284 /** 285 * Publishes an event to the node. This can be either a simple item 286 * with no payload, or one with it. This is determined by the Node 287 * configuration. 288 * 289 * If the node has <b>deliver_payload=false</b>, the Item must not 290 * have a payload. 291 * 292 * If the id is null, an empty item (one without an id) will be sent. 293 * Please note that this is not the same as {@link #send()}, which 294 * publishes an event with NO item. 295 * 296 * @param item - The item being sent 297 * @param <T> type of the items. 298 * 299 * @throws XMPPErrorException 300 * @throws NoResponseException 301 * @throws NotConnectedException 302 * @throws InterruptedException 303 * 304 */ 305 @SuppressWarnings("unchecked") 306 public <T extends Item> void publish(T item) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 307 Collection<T> items = new ArrayList<>(1); 308 items.add((item == null ? (T) new Item() : item)); 309 publish(items); 310 } 311 312 /** 313 * Publishes multiple events to the node. Same rules apply as in {@link #send(Item)}. 314 * 315 * In addition, if {@link ConfigureForm#isPersistItems()}=false, only the last item in the input 316 * list will get stored on the node, assuming it stores the last sent item. 317 * 318 * @param items - The collection of {@link Item} objects being sent 319 * @param <T> type of the items. 320 * 321 * @throws XMPPErrorException 322 * @throws NoResponseException 323 * @throws NotConnectedException 324 * @throws InterruptedException 325 * 326 */ 327 public <T extends Item> void publish(Collection<T> items) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 328 PubSub packet = createPubsubPacket(Type.set, new PublishItem<>(getId(), items)); 329 330 pubSubManager.getConnection().createStanzaCollectorAndSend(packet).nextResultOrThrow(); 331 } 332 333 /** 334 * Purges the node of all items. 335 * 336 * <p>Note: Some implementations may keep the last item 337 * sent. 338 * @throws XMPPErrorException 339 * @throws NoResponseException if there was no response from the server. 340 * @throws NotConnectedException 341 * @throws InterruptedException 342 */ 343 public void deleteAllItems() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 344 PubSub request = createPubsubPacket(Type.set, new NodeExtension(PubSubElementType.PURGE_OWNER, getId())); 345 346 pubSubManager.getConnection().createStanzaCollectorAndSend(request).nextResultOrThrow(); 347 } 348 349 /** 350 * Delete the item with the specified id from the node. 351 * 352 * @param itemId The id of the item 353 * @throws XMPPErrorException 354 * @throws NoResponseException 355 * @throws NotConnectedException 356 * @throws InterruptedException 357 */ 358 public void deleteItem(String itemId) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 359 Collection<String> items = new ArrayList<>(1); 360 items.add(itemId); 361 deleteItem(items); 362 } 363 364 /** 365 * Delete the items with the specified id's from the node. 366 * 367 * @param itemIds The list of id's of items to delete 368 * @throws XMPPErrorException 369 * @throws NoResponseException if there was no response from the server. 370 * @throws NotConnectedException 371 * @throws InterruptedException 372 */ 373 public void deleteItem(Collection<String> itemIds) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 374 List<Item> items = new ArrayList<>(itemIds.size()); 375 376 for (String id : itemIds) { 377 items.add(new Item(id)); 378 } 379 PubSub request = createPubsubPacket(Type.set, new ItemsExtension(ItemsExtension.ItemsElementType.retract, getId(), items)); 380 pubSubManager.getConnection().createStanzaCollectorAndSend(request).nextResultOrThrow(); 381 } 382}