LeafNode.java

  1. /**
  2.  *
  3.  * Copyright the original author or authors
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.jivesoftware.smackx.pubsub;

  18. import java.util.ArrayList;
  19. import java.util.Collection;
  20. import java.util.List;

  21. import org.jivesoftware.smack.SmackException.NoResponseException;
  22. import org.jivesoftware.smack.SmackException.NotConnectedException;
  23. import org.jivesoftware.smack.XMPPException.XMPPErrorException;
  24. import org.jivesoftware.smack.packet.ExtensionElement;
  25. import org.jivesoftware.smack.packet.IQ.Type;

  26. import org.jivesoftware.smackx.disco.packet.DiscoverItems;
  27. import org.jivesoftware.smackx.pubsub.form.ConfigureForm;
  28. import org.jivesoftware.smackx.pubsub.packet.PubSub;

  29. /**
  30.  * The main class for the majority of PubSub functionality. In general
  31.  * almost all PubSub capabilities are related to the concept of a node.
  32.  * All items are published to a node, and typically subscribed to by other
  33.  * users.  These users then retrieve events based on this subscription.
  34.  *
  35.  * @author Robin Collier
  36.  */
  37. public class LeafNode extends Node {
  38.     LeafNode(PubSubManager pubSubManager, String nodeId) {
  39.         super(pubSubManager, nodeId);
  40.     }

  41.     /**
  42.      * Get information on the items in the node in standard
  43.      * {@link DiscoverItems} format.
  44.      *
  45.      * @return The item details in {@link DiscoverItems} format
  46.      * @throws XMPPErrorException if there was an XMPP error returned.
  47.      * @throws NoResponseException if there was no response from the server.
  48.      * @throws NotConnectedException if the XMPP connection is not connected.
  49.      * @throws InterruptedException if the calling thread was interrupted.
  50.      */
  51.     public DiscoverItems discoverItems() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  52.         DiscoverItems items = new DiscoverItems();
  53.         items.setTo(pubSubManager.getServiceJid());
  54.         items.setNode(getId());
  55.         return pubSubManager.getConnection().createStanzaCollectorAndSend(items).nextResultOrThrow();
  56.     }

  57.     /**
  58.      * Get the current items stored in the node.
  59.      *
  60.      * @param <T> type of the items.
  61.      * @return List of {@link Item} in the node
  62.      * @throws XMPPErrorException if there was an XMPP error returned.
  63.      * @throws NoResponseException if there was no response from the server.
  64.      * @throws NotConnectedException if the XMPP connection is not connected.
  65.      * @throws InterruptedException if the calling thread was interrupted.
  66.      */
  67.     public <T extends Item> List<T> getItems() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  68.         return getItems((List<ExtensionElement>) null, null);
  69.     }

  70.     /**
  71.      * Get the current items stored in the node based
  72.      * on the subscription associated with the provided
  73.      * subscription id.
  74.      *
  75.      * @param subscriptionId -  The subscription id for the
  76.      * associated subscription.
  77.      * @param <T> type of the items.
  78.      *
  79.      * @return List of {@link Item} in the node
  80.      * @throws XMPPErrorException if there was an XMPP error returned.
  81.      * @throws NoResponseException if there was no response from the server.
  82.      * @throws NotConnectedException if the XMPP connection is not connected.
  83.      * @throws InterruptedException if the calling thread was interrupted.
  84.      */
  85.     public <T extends Item> List<T> getItems(String subscriptionId) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  86.         PubSub request = createPubsubPacket(Type.get, new GetItemsRequest(getId(), subscriptionId));
  87.         return getItems(request);
  88.     }

  89.     /**
  90.      * Get the items specified from the node.  This would typically be
  91.      * used when the server does not return the payload due to size
  92.      * constraints.  The user would be required to retrieve the payload
  93.      * after the items have been retrieved via {@link #getItems()} or an
  94.      * event, that did not include the payload.
  95.      *
  96.      * @param ids Item ids of the items to retrieve
  97.      * @param <T> type of the items.
  98.      *
  99.      * @return The list of {@link Item} with payload
  100.      * @throws XMPPErrorException if there was an XMPP error returned.
  101.      * @throws NoResponseException if there was no response from the server.
  102.      * @throws NotConnectedException if the XMPP connection is not connected.
  103.      * @throws InterruptedException if the calling thread was interrupted.
  104.      */
  105.     public <T extends Item> List<T> getItems(Collection<String> ids) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  106.         List<Item> itemList = new ArrayList<>(ids.size());

  107.         for (String id : ids) {
  108.             itemList.add(new Item(id));
  109.         }
  110.         PubSub request = createPubsubPacket(Type.get, new ItemsExtension(ItemsExtension.ItemsElementType.items, getId(), itemList));
  111.         return getItems(request);
  112.     }

  113.     /**
  114.      * Get items persisted on the node, limited to the specified number.
  115.      *
  116.      * @param maxItems Maximum number of items to return
  117.      * @param <T> type of the items.
  118.      *
  119.      * @return List of {@link Item}
  120.      * @throws XMPPErrorException if there was an XMPP error returned.
  121.      * @throws NoResponseException if there was no response from the server.
  122.      * @throws NotConnectedException if the XMPP connection is not connected.
  123.      * @throws InterruptedException if the calling thread was interrupted.
  124.      */
  125.     public <T extends Item> List<T> getItems(int maxItems) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  126.         PubSub request = createPubsubPacket(Type.get, new GetItemsRequest(getId(), maxItems));
  127.         return getItems(request);
  128.     }

  129.     /**
  130.      * Get items persisted on the node, limited to the specified number
  131.      * based on the subscription associated with the provided subscriptionId.
  132.      *
  133.      * @param maxItems Maximum number of items to return
  134.      * @param subscriptionId The subscription which the retrieval is based
  135.      * on.
  136.      *
  137.      * @return List of {@link Item}
  138.      * @param <T> type of the items.
  139.      *
  140.      * @throws XMPPErrorException if there was an XMPP error returned.
  141.      * @throws NoResponseException if there was no response from the server.
  142.      * @throws NotConnectedException if the XMPP connection is not connected.
  143.      * @throws InterruptedException if the calling thread was interrupted.
  144.      */
  145.     public <T extends Item> List<T> getItems(int maxItems, String subscriptionId) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  146.         PubSub request = createPubsubPacket(Type.get, new GetItemsRequest(getId(), subscriptionId, maxItems));
  147.         return getItems(request);
  148.     }

  149.     /**
  150.      * Get items persisted on the node.
  151.      * <p>
  152.      * {@code additionalExtensions} can be used e.g. to add a "Result Set Management" extension.
  153.      * {@code returnedExtensions} will be filled with the stanza extensions found in the answer.
  154.      * </p>
  155.      *
  156.      * @param additionalExtensions additional {@code PacketExtensions} to be added to the request.
  157.      *        This is an optional argument, if provided as null no extensions will be added.
  158.      * @param returnedExtensions a collection that will be filled with the returned packet
  159.      *        extensions. This is an optional argument, if provided as null it won't be populated.
  160.      * @param <T> type of the items.
  161.      *
  162.      * @return List of {@link Item}
  163.      * @throws NoResponseException if there was no response from the remote entity.
  164.      * @throws XMPPErrorException if there was an XMPP error returned.
  165.      * @throws NotConnectedException if the XMPP connection is not connected.
  166.      * @throws InterruptedException if the calling thread was interrupted.
  167.      */
  168.     public <T extends Item> List<T> getItems(List<ExtensionElement> additionalExtensions,
  169.                     List<ExtensionElement> returnedExtensions) throws NoResponseException,
  170.                     XMPPErrorException, NotConnectedException, InterruptedException {
  171.         PubSub request = createPubsubPacket(Type.get, new GetItemsRequest(getId()));
  172.         request.addExtensions(additionalExtensions);
  173.         return getItems(request, returnedExtensions);
  174.     }

  175.     private <T extends Item> List<T> getItems(PubSub request) throws NoResponseException,
  176.                     XMPPErrorException, NotConnectedException, InterruptedException {
  177.         return getItems(request, null);
  178.     }

  179.     @SuppressWarnings("unchecked")
  180.     private <T extends Item> List<T> getItems(PubSub request,
  181.                     List<ExtensionElement> returnedExtensions) throws NoResponseException,
  182.                     XMPPErrorException, NotConnectedException, InterruptedException {
  183.         PubSub result = pubSubManager.getConnection().createStanzaCollectorAndSend(request).nextResultOrThrow();
  184.         ItemsExtension itemsElem = result.getExtension(PubSubElementType.ITEMS);
  185.         if (returnedExtensions != null) {
  186.             returnedExtensions.addAll(result.getExtensions());
  187.         }
  188.         return (List<T>) itemsElem.getItems();
  189.     }

  190.     /**
  191.      * Publishes an event to the node.  This is an empty event
  192.      * with no item.
  193.      *
  194.      * This is only acceptable for nodes with {@link ConfigureForm#isPersistItems()}=false
  195.      * and {@link ConfigureForm#isDeliverPayloads()}=false.
  196.      *
  197.      * @throws NotConnectedException if the XMPP connection is not connected.
  198.      * @throws InterruptedException if the calling thread was interrupted.
  199.      * @throws XMPPErrorException if there was an XMPP error returned.
  200.      * @throws NoResponseException if there was no response from the remote entity.
  201.      * @deprecated use {@link #publish()} instead.
  202.      */
  203.     @Deprecated
  204.     public void send() throws NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException {
  205.         publish();
  206.     }

  207.     /**
  208.      * Publishes an event to the node.  This is a simple item
  209.      * with no payload.
  210.      *
  211.      * If the id is null, an empty item (one without an id) will be sent.
  212.      * Please note that this is not the same as {@link #send()}, which
  213.      * publishes an event with NO item.
  214.      *
  215.      * @param item - The item being sent
  216.      * @param <T> type of the items.
  217.      *
  218.      * @throws NotConnectedException if the XMPP connection is not connected.
  219.      * @throws InterruptedException if the calling thread was interrupted.
  220.      * @throws XMPPErrorException if there was an XMPP error returned.
  221.      * @throws NoResponseException if there was no response from the remote entity.
  222.      * @deprecated use {@link #publish(Item)} instead.
  223.      */
  224.     @Deprecated
  225.     public <T extends Item> void send(T item) throws NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException {
  226.         publish(item);
  227.     }

  228.     /**
  229.      * Publishes multiple events to the node.  Same rules apply as in {@link #publish(Item)}.
  230.      *
  231.      * In addition, if {@link ConfigureForm#isPersistItems()}=false, only the last item in the input
  232.      * list will get stored on the node, assuming it stores the last sent item.
  233.      *
  234.      * @param items - The collection of items being sent
  235.      * @param <T> type of the items.
  236.      *
  237.      * @throws NotConnectedException if the XMPP connection is not connected.
  238.      * @throws InterruptedException if the calling thread was interrupted.
  239.      * @throws XMPPErrorException if there was an XMPP error returned.
  240.      * @throws NoResponseException if there was no response from the remote entity.
  241.      * @deprecated use {@link #publish(Collection)} instead.
  242.      */
  243.     @Deprecated
  244.     public <T extends Item> void send(Collection<T> items) throws NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException {
  245.         publish(items);
  246.     }

  247.     /**
  248.      * Publishes an event to the node.  This is an empty event
  249.      * with no item.
  250.      *
  251.      * This is only acceptable for nodes with {@link ConfigureForm#isPersistItems()}=false
  252.      * and {@link ConfigureForm#isDeliverPayloads()}=false.
  253.      *
  254.      * @throws XMPPErrorException if there was an XMPP error returned.
  255.      * @throws NoResponseException if there was no response from the remote entity.
  256.      * @throws NotConnectedException if the XMPP connection is not connected.
  257.      * @throws InterruptedException if the calling thread was interrupted.
  258.      *
  259.      */
  260.     public void publish() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  261.         PubSub packet = createPubsubPacket(Type.set, new NodeExtension(PubSubElementType.PUBLISH, getId()));

  262.         pubSubManager.getConnection().createStanzaCollectorAndSend(packet).nextResultOrThrow();
  263.     }

  264.     /**
  265.      * Publishes an event to the node.  This can be either a simple item
  266.      * with no payload, or one with it.  This is determined by the Node
  267.      * configuration.
  268.      *
  269.      * If the node has <b>deliver_payload=false</b>, the Item must not
  270.      * have a payload.
  271.      *
  272.      * If the id is null, an empty item (one without an id) will be sent.
  273.      * Please note that this is not the same as {@link #send()}, which
  274.      * publishes an event with NO item.
  275.      *
  276.      * @param item - The item being sent
  277.      * @param <T> type of the items.
  278.      *
  279.      * @throws XMPPErrorException if there was an XMPP error returned.
  280.      * @throws NoResponseException if there was no response from the remote entity.
  281.      * @throws NotConnectedException if the XMPP connection is not connected.
  282.      * @throws InterruptedException if the calling thread was interrupted.
  283.      *
  284.      */
  285.     @SuppressWarnings("unchecked")
  286.     public <T extends Item> void publish(T item) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  287.         Collection<T> items = new ArrayList<>(1);
  288.         items.add(item == null ? (T) new Item() : item);
  289.         publish(items);
  290.     }

  291.     /**
  292.      * Publishes multiple events to the node.  Same rules apply as in {@link #send(Item)}.
  293.      *
  294.      * In addition, if {@link ConfigureForm#isPersistItems()}=false, only the last item in the input
  295.      * list will get stored on the node, assuming it stores the last sent item.
  296.      *
  297.      * @param items - The collection of {@link Item} objects being sent
  298.      * @param <T> type of the items.
  299.      *
  300.      * @throws XMPPErrorException if there was an XMPP error returned.
  301.      * @throws NoResponseException if there was no response from the remote entity.
  302.      * @throws NotConnectedException if the XMPP connection is not connected.
  303.      * @throws InterruptedException if the calling thread was interrupted.
  304.      *
  305.      */
  306.     public <T extends Item> void publish(Collection<T> items) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  307.         PubSub packet = createPubsubPacket(Type.set, new PublishItem<>(getId(), items));

  308.         pubSubManager.getConnection().createStanzaCollectorAndSend(packet).nextResultOrThrow();
  309.     }

  310.     /**
  311.      * Purges the node of all items.
  312.      *
  313.      * <p>Note: Some implementations may keep the last item
  314.      * sent.
  315.      * @throws XMPPErrorException if there was an XMPP error returned.
  316.      * @throws NoResponseException if there was no response from the server.
  317.      * @throws NotConnectedException if the XMPP connection is not connected.
  318.      * @throws InterruptedException if the calling thread was interrupted.
  319.      */
  320.     public void deleteAllItems() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  321.         PubSub request = createPubsubPacket(Type.set, new NodeExtension(PubSubElementType.PURGE_OWNER, getId()));

  322.         pubSubManager.getConnection().createStanzaCollectorAndSend(request).nextResultOrThrow();
  323.     }

  324.     /**
  325.      * Delete the item with the specified id from the node.
  326.      *
  327.      * @param itemId The id of the item
  328.      * @throws XMPPErrorException if there was an XMPP error returned.
  329.      * @throws NoResponseException if there was no response from the remote entity.
  330.      * @throws NotConnectedException if the XMPP connection is not connected.
  331.      * @throws InterruptedException if the calling thread was interrupted.
  332.      */
  333.     public void deleteItem(String itemId) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  334.         Collection<String> items = new ArrayList<>(1);
  335.         items.add(itemId);
  336.         deleteItem(items);
  337.     }

  338.     /**
  339.      * Delete the items with the specified id's from the node.
  340.      *
  341.      * @param itemIds The list of id's of items to delete
  342.      * @throws XMPPErrorException if there was an XMPP error returned.
  343.      * @throws NoResponseException if there was no response from the server.
  344.      * @throws NotConnectedException if the XMPP connection is not connected.
  345.      * @throws InterruptedException if the calling thread was interrupted.
  346.      */
  347.     public void deleteItem(Collection<String> itemIds) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  348.         List<Item> items = new ArrayList<>(itemIds.size());

  349.         for (String id : itemIds) {
  350.              items.add(new Item(id));
  351.         }
  352.         PubSub request = createPubsubPacket(Type.set, new ItemsExtension(ItemsExtension.ItemsElementType.retract, getId(), items));
  353.         pubSubManager.getConnection().createStanzaCollectorAndSend(request).nextResultOrThrow();
  354.     }
  355. }