Package org.jivesoftware.smackx.pubsub

Source Code of org.jivesoftware.smackx.pubsub.Node$ItemDeleteTranslator

/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright 2009 Robin Collier.
*
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.pubsub;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.OrFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smackx.Form;
import org.jivesoftware.smackx.packet.DelayInformation;
import org.jivesoftware.smackx.packet.DiscoverInfo;
import org.jivesoftware.smackx.packet.Header;
import org.jivesoftware.smackx.packet.HeadersExtension;
import org.jivesoftware.smackx.pubsub.listener.ItemDeleteListener;
import org.jivesoftware.smackx.pubsub.listener.ItemEventListener;
import org.jivesoftware.smackx.pubsub.listener.NodeConfigListener;
import org.jivesoftware.smackx.pubsub.packet.PubSub;
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
import org.jivesoftware.smackx.pubsub.util.NodeUtils;

abstract public class Node
{
  protected Connection con;
  protected String id;
  protected String to;
 
  protected ConcurrentHashMap<ItemEventListener<Item>, PacketListener> itemEventToListenerMap = new ConcurrentHashMap<ItemEventListener<Item>, PacketListener>();
  protected ConcurrentHashMap<ItemDeleteListener, PacketListener> itemDeleteToListenerMap = new ConcurrentHashMap<ItemDeleteListener, PacketListener>();
  protected ConcurrentHashMap<NodeConfigListener, PacketListener> configEventToListenerMap = new ConcurrentHashMap<NodeConfigListener, PacketListener>();
 
  /**
   * Construct a node associated to the supplied connection with the specified
   * node id.
   *
   * @param connection The connection the node is associated with
   * @param nodeName The node id
   */
  Node(Connection connection, String nodeName)
  {
    con = connection;
    id = nodeName;
  }

  /**
   * Some XMPP servers may require a specific service to be addressed on the
   * server.
   *
   *   For example, OpenFire requires the server to be prefixed by <b>pubsub</b>
   */
  void setTo(String toAddress)
  {
    to = toAddress;
  }

  /**
   * Get the NodeId
   *
   * @return the node id
   */
  public String getId()
  {
    return id;
  }
  /**
   * Returns a configuration form, from which you can create an answer form to be submitted
   * via the {@link #sendConfigurationForm(Form)}.
   *
   * @return the configuration form
   */
  public ConfigureForm getNodeConfiguration()
    throws XMPPException
  {
    Packet reply = sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.CONFIGURE_OWNER, getId()), PubSubNamespace.OWNER);
    return NodeUtils.getFormFromPacket(reply, PubSubElementType.CONFIGURE_OWNER);
  }
 
  /**
   * Update the configuration with the contents of the new {@link Form}
   *
   * @param submitForm
   */
  public void sendConfigurationForm(Form submitForm)
    throws XMPPException
  {
    PubSub packet = createPubsubPacket(Type.SET, new FormNode(FormNodeType.CONFIGURE_OWNER, getId(), submitForm), PubSubNamespace.OWNER);
    SyncPacketSend.getReply(con, packet);
  }
 
  /**
   * Discover node information in standard {@link DiscoverInfo} format.
   *
   * @return The discovery information about the node.
   *
   * @throws XMPPException
   */
  public DiscoverInfo discoverInfo()
    throws XMPPException
  {
    DiscoverInfo info = new DiscoverInfo();
    info.setTo(to);
    info.setNode(getId());
    return (DiscoverInfo)SyncPacketSend.getReply(con, info);
  }
 
  /**
   * Get the subscriptions currently associated with this node.
   *
   * @return List of {@link Subscription}
   *
   * @throws XMPPException
   */
  public List<Subscription> getSubscriptions()
    throws XMPPException
  {
    PubSub reply = (PubSub)sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.SUBSCRIPTIONS, getId()));
    SubscriptionsExtension subElem = (SubscriptionsExtension)reply.getExtension(PubSubElementType.SUBSCRIPTIONS);
    return subElem.getSubscriptions();
  }

  /**
   * The user subscribes to the node using the supplied jid.  The
   * bare jid portion of this one must match the jid for the connection.
   *
   * Please note that the {@link Subscription.State} should be checked
   * on return since more actions may be required by the caller.
   * {@link Subscription.State#pending} - The owner must approve the subscription
   * request before messages will be received.
   * {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true,
   * the caller must configure the subscription before messages will be received.  If it is false
   * the caller can configure it but is not required to do so.
   * @param jid The jid to subscribe as.
   * @return The subscription
   * @exception XMPPException
   */
  public Subscription subscribe(String jid)
    throws XMPPException
  {
    PubSub reply = (PubSub)sendPubsubPacket(Type.SET, new SubscribeExtension(jid, getId()));
    return (Subscription)reply.getExtension(PubSubElementType.SUBSCRIPTION);
  }
 
  /**
   * The user subscribes to the node using the supplied jid and subscription
   * options.  The bare jid portion of this one must match the jid for the
   * connection.
   *
   * Please note that the {@link Subscription.State} should be checked
   * on return since more actions may be required by the caller.
   * {@link Subscription.State#pending} - The owner must approve the subscription
   * request before messages will be received.
   * {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true,
   * the caller must configure the subscription before messages will be received.  If it is false
   * the caller can configure it but is not required to do so.
   * @param jid The jid to subscribe as.
   * @return The subscription
   * @exception XMPPException
   */
  public Subscription subscribe(String jid, SubscribeForm subForm)
    throws XMPPException
  {
    PubSub request = createPubsubPacket(Type.SET, new SubscribeExtension(jid, getId()));
    request.addExtension(new FormNode(FormNodeType.OPTIONS, subForm));
    PubSub reply = (PubSub)PubSubManager.sendPubsubPacket(con, jid, Type.SET, request);
    return (Subscription)reply.getExtension(PubSubElementType.SUBSCRIPTION);
  }

  /**
   * Remove the subscription related to the specified JID.  This will only
   * work if there is only 1 subscription.  If there are multiple subscriptions,
   * use {@link #unsubscribe(String, String)}.
   *
   * @param jid The JID used to subscribe to the node
   *
   * @throws XMPPException
   */
  public void unsubscribe(String jid)
    throws XMPPException
  {
    unsubscribe(jid, null);
  }
 
  /**
   * Remove the specific subscription related to the specified JID.
   *
   * @param jid The JID used to subscribe to the node
   * @param subscriptionId The id of the subscription being removed
   *
   * @throws XMPPException
   */
  public void unsubscribe(String jid, String subscriptionId)
    throws XMPPException
  {
    sendPubsubPacket(Type.SET, new UnsubscribeExtension(jid, getId(), subscriptionId));
  }

  /**
   * Returns a SubscribeForm for subscriptions, from which you can create an answer form to be submitted
   * via the {@link #sendConfigurationForm(Form)}.
   *
   * @return A subscription options form
   *
   * @throws XMPPException
   */
  public SubscribeForm getSubscriptionOptions(String jid)
    throws XMPPException
  {
    return getSubscriptionOptions(jid, null);
  }


  /**
   * Get the options for configuring the specified subscription.
   *
   * @param jid JID the subscription is registered under
   * @param subscriptionId The subscription id
   *
   * @return The subscription option form
   *
   * @throws XMPPException
   */
  public SubscribeForm getSubscriptionOptions(String jid, String subscriptionId)
    throws XMPPException
  {
    PubSub packet = (PubSub)sendPubsubPacket(Type.GET, new OptionsExtension(jid, getId(), subscriptionId));
    FormNode ext = (FormNode)packet.getExtension(PubSubElementType.OPTIONS);
    return new SubscribeForm(ext.getForm());
  }

  /**
   * Register a listener for item publication events.  This
   * listener will get called whenever an item is published to
   * this node.
   *
   * @param listener The handler for the event
   */
  public void addItemEventListener(ItemEventListener listener)
  {
    PacketListener conListener = new ItemEventTranslator(listener);
    itemEventToListenerMap.put(listener, conListener);
    con.addPacketListener(conListener, new EventContentFilter(EventElementType.items.toString(), "item"));
  }

  /**
   * Unregister a listener for publication events.
   *
   * @param listener The handler to unregister
   */
  public void removeItemEventListener(ItemEventListener listener)
  {
    PacketListener conListener = itemEventToListenerMap.remove(listener);
   
    if (conListener != null)
      con.removePacketListener(conListener);
  }

  /**
   * Register a listener for configuration events.  This listener
   * will get called whenever the node's configuration changes.
   *
   * @param listener The handler for the event
   */
  public void addConfigurationListener(NodeConfigListener listener)
  {
    PacketListener conListener = new NodeConfigTranslator(listener);
    configEventToListenerMap.put(listener, conListener);
    con.addPacketListener(conListener, new EventContentFilter(EventElementType.configuration.toString()));
  }

  /**
   * Unregister a listener for configuration events.
   *
   * @param listener The handler to unregister
   */
  public void removeConfigurationListener(NodeConfigListener listener)
  {
    PacketListener conListener = configEventToListenerMap .remove(listener);
   
    if (conListener != null)
      con.removePacketListener(conListener);
  }
 
  /**
   * Register an listener for item delete events.  This listener
   * gets called whenever an item is deleted from the node.
   *
   * @param listener The handler for the event
   */
  public void addItemDeleteListener(ItemDeleteListener listener)
  {
    PacketListener delListener = new ItemDeleteTranslator(listener);
    itemDeleteToListenerMap.put(listener, delListener);
    EventContentFilter deleteItem = new EventContentFilter(EventElementType.items.toString(), "retract");
    EventContentFilter purge = new EventContentFilter(EventElementType.purge.toString());
   
    con.addPacketListener(delListener, new OrFilter(deleteItem, purge));
  }

  /**
   * Unregister a listener for item delete events.
   *
   * @param listener The handler to unregister
   */
  public void removeItemDeleteListener(ItemDeleteListener listener)
  {
    PacketListener conListener = itemDeleteToListenerMap .remove(listener);
   
    if (conListener != null)
      con.removePacketListener(conListener);
  }

  @Override
  public String toString()
  {
    return super.toString() + " " + getClass().getName() + " id: " + id;
  }
 
  protected PubSub createPubsubPacket(Type type, PacketExtension ext)
  {
    return createPubsubPacket(type, ext, null);
  }
 
  protected PubSub createPubsubPacket(Type type, PacketExtension ext, PubSubNamespace ns)
  {
    return PubSubManager.createPubsubPacket(to, type, ext, ns);
  }

  protected Packet sendPubsubPacket(Type type, NodeExtension ext)
    throws XMPPException
  {
    return PubSubManager.sendPubsubPacket(con, to, type, ext);
  }

  protected Packet sendPubsubPacket(Type type, NodeExtension ext, PubSubNamespace ns)
    throws XMPPException
  {
    return PubSubManager.sendPubsubPacket(con, to, type, ext, ns);
  }


  private static List<String> getSubscriptionIds(Packet packet)
  {
    HeadersExtension headers = (HeadersExtension)packet.getExtension("headers", "http://jabber.org/protocol/shim");
    List<String> values = null;
   
    if (headers != null)
    {
      values = new ArrayList<String>(headers.getHeaders().size());
     
      for (Header header : headers.getHeaders())
      {
        values.add(header.getValue());
      }
    }
    return values;
  }

  /**
   * This class translates low level item publication events into api level objects for
   * user consumption.
   *
   * @author Robin Collier
   */
  public class ItemEventTranslator implements PacketListener
  {
    private ItemEventListener listener;

    public ItemEventTranslator(ItemEventListener eventListener)
    {
      listener = eventListener;
    }
   
    public void processPacket(Packet packet)
    {
          EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
      ItemsExtension itemsElem = (ItemsExtension)event.getEvent();
      DelayInformation delay = (DelayInformation)packet.getExtension("delay", "urn:xmpp:delay");
     
      // If there was no delay based on XEP-0203, then try XEP-0091 for backward compatibility
      if (delay == null)
      {
        delay = (DelayInformation)packet.getExtension("x", "jabber:x:delay");
      }
      ItemPublishEvent eventItems = new ItemPublishEvent(itemsElem.getNode(), (List<Item>)itemsElem.getItems(), getSubscriptionIds(packet), (delay == null ? null : delay.getStamp()));
      listener.handlePublishedItems(eventItems);
    }
  }

  /**
   * This class translates low level item deletion events into api level objects for
   * user consumption.
   *
   * @author Robin Collier
   */
  public class ItemDeleteTranslator implements PacketListener
  {
    private ItemDeleteListener listener;

    public ItemDeleteTranslator(ItemDeleteListener eventListener)
    {
      listener = eventListener;
    }
   
    public void processPacket(Packet packet)
    {
          EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
         
          List<PacketExtension> extList = event.getExtensions();
         
          if (extList.get(0).getElementName().equals(PubSubElementType.PURGE_EVENT.getElementName()))
          {
            listener.handlePurge();
          }
          else
          {
        ItemsExtension itemsElem = (ItemsExtension)event.getEvent();
        Collection<? extends PacketExtension> pubItems = itemsElem.getItems();
        Iterator<RetractItem> it = (Iterator<RetractItem>)pubItems.iterator();
        List<String> items = new ArrayList<String>(pubItems.size());

        while (it.hasNext())
        {
          RetractItem item = it.next();
          items.add(item.getId());
        }

        ItemDeleteEvent eventItems = new ItemDeleteEvent(itemsElem.getNode(), items, getSubscriptionIds(packet));
        listener.handleDeletedItems(eventItems);
          }
    }
  }
 
  /**
   * This class translates low level node configuration events into api level objects for
   * user consumption.
   *
   * @author Robin Collier
   */
  public class NodeConfigTranslator implements PacketListener
  {
    private NodeConfigListener listener;

    public NodeConfigTranslator(NodeConfigListener eventListener)
    {
      listener = eventListener;
    }
   
    public void processPacket(Packet packet)
    {
          EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
      ConfigurationEvent config = (ConfigurationEvent)event.getEvent();

      listener.handleNodeConfiguration(config);
    }
  }

  /**
   * Filter for {@link PacketListener} to filter out events not specific to the
   * event type expected for this node.
   *
   * @author Robin Collier
   */
  class EventContentFilter implements PacketFilter
  {
    private String firstElement;
    private String secondElement;
   
    EventContentFilter(String elementName)
    {
      firstElement = elementName;
    }

    EventContentFilter(String firstLevelEelement, String secondLevelElement)
    {
      firstElement = firstLevelEelement;
      secondElement = secondLevelElement;
    }

    public boolean accept(Packet packet)
    {
      if (!(packet instanceof Message))
        return false;

      EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
     
      if (event == null)
        return false;

      NodeExtension embedEvent = event.getEvent();
     
      if (embedEvent == null)
        return false;
     
      if (embedEvent.getElementName().equals(firstElement))
      {
        if (!embedEvent.getNode().equals(getId()))
          return false;
       
        if (secondElement == null)
          return true;
       
        if (embedEvent instanceof EmbeddedPacketExtension)
        {
          List<PacketExtension> secondLevelList = ((EmbeddedPacketExtension)embedEvent).getExtensions();
         
          if (secondLevelList.size() > 0 && secondLevelList.get(0).getElementName().equals(secondElement))
            return true;
        }
      }
      return false;
    }
  }
}
TOP

Related Classes of org.jivesoftware.smackx.pubsub.Node$ItemDeleteTranslator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.