/**
  * Returns true if events in general can be sent. This method checks basic conditions common to
  * all type of event notifications (e.g. item was published, node configuration has changed, new
  * child node was added to collection node, etc.).
  *
  * @return true if events in general can be sent.
  */
 private boolean canSendEvents() {
   // Check if the subscription is active
   if (!isActive()) {
     return false;
   }
   // Check if delivery of notifications is disabled
   if (!shouldDeliverNotifications()) {
     return false;
   }
   // Check if delivery is subject to presence-based policy
   if (!getPresenceStates().isEmpty()) {
     Collection<String> shows = service.getShowPresences(jid);
     if (shows.isEmpty() || Collections.disjoint(getPresenceStates(), shows)) {
       return false;
     }
   }
   // Check if node is only sending events when user is online
   if (node.isPresenceBasedDelivery()) {
     // Check that user is online
     if (service.getShowPresences(jid).isEmpty()) {
       return false;
     }
   }
   return true;
 }
 /**
  * Sends an request to authorize the pending subscription to the specified owner.
  *
  * @param owner the JID of the user that will get the authorization request.
  */
 public void sendAuthorizationRequest(JID owner) {
   Message authRequest = new Message();
   authRequest.addExtension(node.getAuthRequestForm(this));
   authRequest.setTo(owner);
   authRequest.setFrom(service.getAddress());
   // Send authentication request to node owners
   service.send(authRequest);
 }
 /**
  * Sends an event notification for the last published item to the subscriber. If the subscription
  * has not yet been authorized or is pending to be configured then no notification is going to be
  * sent.
  *
  * <p>Depending on the subscription configuration the event notification may or may not have a
  * payload, may not be sent if a keyword (i.e. filter) was defined and it was not matched.
  *
  * @param publishedItem the last item that was published to the node.
  */
 void sendLastPublishedItem(PublishedItem publishedItem) {
   // Check if the published item can be sent to the subscriber
   if (!canSendPublicationEvent(publishedItem.getNode(), publishedItem)) {
     return;
   }
   // Send event notification to the subscriber
   Message notification = new Message();
   Element event =
       notification.getElement().addElement("event", "http://jabber.org/protocol/pubsub#event");
   Element items = event.addElement("items");
   items.addAttribute("node", node.getNodeID());
   Element item = items.addElement("item");
   if (((LeafNode) node).isItemRequired()) {
     item.addAttribute("id", publishedItem.getID());
   }
   if (node.isPayloadDelivered() && publishedItem.getPayload() != null) {
     item.add(publishedItem.getPayload().createCopy());
   }
   // Add a message body (if required)
   if (isIncludingBody()) {
     notification.setBody(LocaleUtils.getLocalizedString("pubsub.notification.message.body"));
   }
   // Include date when published item was created
   notification
       .getElement()
       .addElement("delay", "urn:xmpp:delay")
       .addAttribute("stamp", fastDateFormat.format(publishedItem.getCreationDate()));
   // Send the event notification to the subscriber
   service.sendNotification(node, notification, jid);
 }
  /**
   * Configures the subscription based on the sent {@link DataForm} included in the IQ packet sent
   * by the subscriber. If the subscription was pending of configuration then the last published
   * item is going to be sent to the subscriber.
   *
   * <p>The originalIQ parameter may be <tt>null</tt> when using this API internally. When no IQ
   * packet was sent then no IQ result will be sent to the sender. The rest of the functionality is
   * the same.
   *
   * @param originalIQ the IQ packet sent by the subscriber to configure his subscription or null
   *     when using this API internally.
   * @param options the data form containing the new subscription configuration.
   */
  public void configure(IQ originalIQ, DataForm options) {
    boolean wasUnconfigured = isConfigurationPending();
    // Change the subscription configuration based on the completed form
    configure(options);
    if (originalIQ != null) {
      // Return success response
      service.send(IQ.createResultIQ(originalIQ));
    }

    if (wasUnconfigured) {
      // If subscription is pending then send notification to node owners
      // asking to approve the now configured subscription
      if (isAuthorizationPending()) {
        sendAuthorizationRequest();
      }

      // Send last published item (if node is leaf node and subscription status is ok)
      if (node.isSendItemSubscribe() && isActive()) {
        PublishedItem lastItem = node.getLastPublishedItem();
        if (lastItem != null) {
          sendLastPublishedItem(lastItem);
        }
      }
    }
  }
 /**
  * Sends the current subscription status to the user that tried to create a subscription to the
  * node. The subscription status is sent to the subsciber after the subscription was created or if
  * the subscriber tries to subscribe many times and the node does not support multpiple
  * subscriptions.
  *
  * @param originalRequest the IQ packet sent by the subscriber to create the subscription.
  */
 void sendSubscriptionState(IQ originalRequest) {
   IQ result = IQ.createResultIQ(originalRequest);
   Element child = result.setChildElement("pubsub", "http://jabber.org/protocol/pubsub");
   Element entity = child.addElement("subscription");
   if (!node.isRootCollectionNode()) {
     entity.addAttribute("node", node.getNodeID());
   }
   entity.addAttribute("jid", getJID().toString());
   if (node.isMultipleSubscriptionsEnabled()) {
     entity.addAttribute("subid", getID());
   }
   entity.addAttribute("subscription", getState().name());
   Element subscribeOptions = entity.addElement("subscribe-options");
   if (node.isSubscriptionConfigurationRequired() && isConfigurationPending()) {
     subscribeOptions.addElement("required");
   }
   // Send the result
   service.send(result);
 }
 @JmsListener(destination = "simpleTopic")
 public void readMessage(String message) {
   pubSubService.processText(1, message);
 }
 /**
  * Sends an request to authorize the pending subscription to all owners. The first answer sent by
  * a owner will be processed. Rest of the answers will be discarded.
  */
 public void sendAuthorizationRequest() {
   Message authRequest = new Message();
   authRequest.addExtension(node.getAuthRequestForm(this));
   // Send authentication request to node owners
   service.broadcast(node, authRequest, node.getOwners());
 }
 /**
  * Returns true if the specified user is allowed to modify or cancel the subscription. Users that
  * are allowed to modify/cancel the subscription are: the entity that is recieving the
  * notifications, the owner of the subscriptions or sysadmins of the pubsub service.
  *
  * @param user the user that is trying to cancel the subscription.
  * @return true if the specified user is allowed to modify or cancel the subscription.
  */
 boolean canModify(JID user) {
   return user.equals(getJID()) || user.equals(getOwner()) || service.isServiceAdmin(user);
 }
  void configure(DataForm options) {
    List<String> values;
    String booleanValue;

    boolean wasUsingPresence = !presenceStates.isEmpty();

    // Remove this field from the form
    options.removeField("FORM_TYPE");
    // Process and remove specific collection node fields
    FormField collectionField = options.getField("pubsub#subscription_type");
    if (collectionField != null) {
      values = collectionField.getValues();
      if (values.size() > 0) {
        type = Type.valueOf(values.get(0));
      }
      options.removeField("pubsub#subscription_type");
    }
    collectionField = options.getField("pubsub#subscription_depth");
    if (collectionField != null) {
      values = collectionField.getValues();
      depth = "all".equals(values.get(0)) ? 0 : 1;
      options.removeField("pubsub#subscription_depth");
    }
    // If there are more fields in the form then process them and set that
    // the subscription has been configured
    for (FormField field : options.getFields()) {
      boolean fieldExists = true;
      if ("pubsub#deliver".equals(field.getVariable())) {
        values = field.getValues();
        booleanValue = (values.size() > 0 ? values.get(0) : "1");
        deliverNotifications = "1".equals(booleanValue);
      } else if ("pubsub#digest".equals(field.getVariable())) {
        values = field.getValues();
        booleanValue = (values.size() > 0 ? values.get(0) : "1");
        usingDigest = "1".equals(booleanValue);
      } else if ("pubsub#digest_frequency".equals(field.getVariable())) {
        values = field.getValues();
        digestFrequency = values.size() > 0 ? Integer.parseInt(values.get(0)) : 86400000;
      } else if ("pubsub#expire".equals(field.getVariable())) {
        values = field.getValues();
        synchronized (dateFormat) {
          try {
            expire = dateFormat.parse(values.get(0));
          } catch (ParseException e) {
            Log.error("Error parsing date", e);
          }
        }
      } else if ("pubsub#include_body".equals(field.getVariable())) {
        values = field.getValues();
        booleanValue = (values.size() > 0 ? values.get(0) : "1");
        includingBody = "1".equals(booleanValue);
      } else if ("pubsub#show-values".equals(field.getVariable())) {
        // Get the new list of presence states for which an entity wants to
        // receive notifications
        presenceStates = new ArrayList<String>();
        for (String value : field.getValues()) {
          try {
            presenceStates.add(value);
          } catch (Exception e) {
            // Do nothing
          }
        }
      } else if ("x-pubsub#keywords".equals(field.getVariable())) {
        values = field.getValues();
        keyword = values.isEmpty() ? null : values.get(0);
      } else {
        fieldExists = false;
      }
      if (fieldExists) {
        // Subscription has been configured so set the next state
        if (node.getAccessModel().isAuthorizationRequired() && !node.isAdmin(owner)) {
          state = State.pending;
        } else {
          state = State.subscribed;
        }
      }
    }
    if (savedToDB) {
      // Update the subscription in the backend store
      PubSubPersistenceManager.saveSubscription(service, node, this, false);
    }
    // Check if the service needs to subscribe or unsubscribe from the owner presence
    if (!node.isPresenceBasedDelivery() && wasUsingPresence != !presenceStates.isEmpty()) {
      if (presenceStates.isEmpty()) {
        service.presenceSubscriptionNotRequired(node, owner);
      } else {
        service.presenceSubscriptionRequired(node, owner);
      }
    }
  }