2013-02-07 15:19:47 +01:00
|
|
|
/**
|
|
|
|
*
|
2013-04-07 21:15:32 +02:00
|
|
|
* Copyright 2009 Robin Collier.
|
2013-02-07 15:19:47 +01:00
|
|
|
*
|
2014-02-17 18:57:38 +01:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
2013-02-07 15:19:47 +01:00
|
|
|
* 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.
|
|
|
|
*/
|
2014-02-17 23:58:40 +01:00
|
|
|
package org.jivesoftware.smackx.pubsub;
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
2014-03-12 11:50:05 +01:00
|
|
|
import org.jivesoftware.smack.SmackException.NoResponseException;
|
2014-03-19 14:22:20 +01:00
|
|
|
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
2017-06-14 17:12:43 +02:00
|
|
|
import org.jivesoftware.smack.StanzaListener;
|
2019-10-29 11:14:55 +01:00
|
|
|
import org.jivesoftware.smack.XMPPConnection;
|
2014-03-12 11:50:05 +01:00
|
|
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
2015-12-06 22:48:22 +01:00
|
|
|
import org.jivesoftware.smack.filter.FlexibleStanzaTypeFilter;
|
2014-02-17 23:58:40 +01:00
|
|
|
import org.jivesoftware.smack.filter.OrFilter;
|
2015-02-26 18:41:17 +01:00
|
|
|
import org.jivesoftware.smack.packet.ExtensionElement;
|
2014-02-17 23:58:40 +01:00
|
|
|
import org.jivesoftware.smack.packet.IQ.Type;
|
2017-06-14 17:12:43 +02:00
|
|
|
import org.jivesoftware.smack.packet.Message;
|
|
|
|
import org.jivesoftware.smack.packet.Stanza;
|
|
|
|
|
2014-06-30 13:36:49 +02:00
|
|
|
import org.jivesoftware.smackx.delay.DelayInformationManager;
|
2014-02-15 11:35:08 +01:00
|
|
|
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
2018-04-19 11:05:43 +02:00
|
|
|
import org.jivesoftware.smackx.pubsub.Affiliation.AffiliationNamespace;
|
|
|
|
import org.jivesoftware.smackx.pubsub.SubscriptionsExtension.SubscriptionsNamespace;
|
2020-05-13 20:14:41 +02:00
|
|
|
import org.jivesoftware.smackx.pubsub.form.ConfigureForm;
|
|
|
|
import org.jivesoftware.smackx.pubsub.form.FillableConfigureForm;
|
|
|
|
import org.jivesoftware.smackx.pubsub.form.FillableSubscribeForm;
|
|
|
|
import org.jivesoftware.smackx.pubsub.form.SubscribeForm;
|
2014-02-17 23:58:40 +01:00
|
|
|
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.util.NodeUtils;
|
2014-02-15 11:35:08 +01:00
|
|
|
import org.jivesoftware.smackx.shim.packet.Header;
|
|
|
|
import org.jivesoftware.smackx.shim.packet.HeadersExtension;
|
2020-05-13 20:14:41 +02:00
|
|
|
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2019-07-05 11:24:02 +02:00
|
|
|
import org.jxmpp.jid.Jid;
|
|
|
|
import org.jxmpp.jid.impl.JidCreate;
|
|
|
|
import org.jxmpp.stringprep.XmppStringprepException;
|
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
public abstract class Node {
|
2015-05-12 17:56:06 +02:00
|
|
|
protected final PubSubManager pubSubManager;
|
|
|
|
protected final String id;
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2017-12-13 23:10:11 +01:00
|
|
|
protected ConcurrentHashMap<ItemEventListener<Item>, StanzaListener> itemEventToListenerMap = new ConcurrentHashMap<>();
|
|
|
|
protected ConcurrentHashMap<ItemDeleteListener, StanzaListener> itemDeleteToListenerMap = new ConcurrentHashMap<>();
|
|
|
|
protected ConcurrentHashMap<NodeConfigListener, StanzaListener> configEventToListenerMap = new ConcurrentHashMap<>();
|
2017-02-07 22:02:40 +01:00
|
|
|
|
|
|
|
/**
|
2018-05-09 23:06:12 +02:00
|
|
|
* Construct a node associated to the supplied connection with the specified
|
2017-02-07 22:02:40 +01:00
|
|
|
* node id.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-12-13 23:10:11 +01:00
|
|
|
* @param pubSubManager The PubSubManager for the connection the node is associated with
|
|
|
|
* @param nodeId The node id
|
2017-02-07 22:02:40 +01:00
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
Node(PubSubManager pubSubManager, String nodeId) {
|
2017-02-07 22:02:40 +01:00
|
|
|
this.pubSubManager = pubSubManager;
|
|
|
|
id = nodeId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the NodeId.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @return the node id
|
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public String getId() {
|
2017-02-07 22:02:40 +01:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Returns a configuration form, from which you can create an answer form to be submitted
|
2020-05-13 20:14:41 +02:00
|
|
|
* via the {@link #sendConfigurationForm(FillableConfigureForm)}.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @return the configuration form
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2017-02-07 22:02:40 +01:00
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public ConfigureForm getNodeConfiguration() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2014-07-14 14:31:09 +02:00
|
|
|
PubSub pubSub = createPubsubPacket(Type.get, new NodeExtension(
|
2018-04-19 11:05:43 +02:00
|
|
|
PubSubElementType.CONFIGURE_OWNER, getId()));
|
2017-02-07 22:02:40 +01:00
|
|
|
Stanza reply = sendPubsubPacket(pubSub);
|
|
|
|
return NodeUtils.getFormFromPacket(reply, PubSubElementType.CONFIGURE_OWNER);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-05-13 20:14:41 +02:00
|
|
|
* Update the configuration with the contents of the new {@link FillableConfigureForm}.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2020-05-13 20:14:41 +02:00
|
|
|
* @param configureForm the filled node configuration form with the nodes new configuration.
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2017-02-07 22:02:40 +01:00
|
|
|
*/
|
2020-05-13 20:14:41 +02:00
|
|
|
public void sendConfigurationForm(FillableConfigureForm configureForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2014-07-14 14:31:09 +02:00
|
|
|
PubSub packet = createPubsubPacket(Type.set, new FormNode(FormNodeType.CONFIGURE_OWNER,
|
2020-05-13 20:14:41 +02:00
|
|
|
getId(), configureForm.getDataFormToSubmit()));
|
2017-01-03 11:12:34 +01:00
|
|
|
pubSubManager.getConnection().createStanzaCollectorAndSend(packet).nextResultOrThrow();
|
2017-02-07 22:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Discover node information in standard {@link DiscoverInfo} format.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @return The discovery information about the node.
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
2017-02-07 22:02:40 +01:00
|
|
|
* @throws NoResponseException if there was no response from the server.
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2017-02-07 22:02:40 +01:00
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public DiscoverInfo discoverInfo() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2019-10-29 11:14:55 +01:00
|
|
|
XMPPConnection connection = pubSubManager.getConnection();
|
|
|
|
DiscoverInfo discoverInfoRequest = DiscoverInfo.builder(connection)
|
|
|
|
.to(pubSubManager.getServiceJid())
|
|
|
|
.setNode(getId())
|
|
|
|
.build();
|
|
|
|
return connection.createStanzaCollectorAndSend(discoverInfoRequest).nextResultOrThrow();
|
2017-02-07 22:02:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the subscriptions currently associated with this node.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @return List of {@link Subscription}
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public List<Subscription> getSubscriptions() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2014-07-09 12:57:51 +02:00
|
|
|
return getSubscriptions(null, null);
|
2017-02-07 22:02:40 +01:00
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2014-07-09 12:57:51 +02:00
|
|
|
/**
|
|
|
|
* Get the subscriptions currently associated with this node.
|
|
|
|
* <p>
|
|
|
|
* {@code additionalExtensions} can be used e.g. to add a "Result Set Management" extension.
|
2018-03-31 14:17:30 +02:00
|
|
|
* {@code returnedExtensions} will be filled with the stanza extensions found in the answer.
|
2014-07-09 12:57:51 +02:00
|
|
|
* </p>
|
|
|
|
*
|
2019-08-30 12:08:30 +02:00
|
|
|
* @param additionalExtensions TODO javadoc me please
|
2014-07-09 12:57:51 +02:00
|
|
|
* @param returnedExtensions a collection that will be filled with the returned packet
|
|
|
|
* extensions
|
|
|
|
* @return List of {@link Subscription}
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2014-07-09 12:57:51 +02:00
|
|
|
*/
|
2015-02-26 18:41:17 +01:00
|
|
|
public List<Subscription> getSubscriptions(List<ExtensionElement> additionalExtensions, Collection<ExtensionElement> returnedExtensions)
|
2015-02-14 09:43:44 +01:00
|
|
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2018-04-19 11:05:43 +02:00
|
|
|
return getSubscriptions(SubscriptionsNamespace.basic, additionalExtensions, returnedExtensions);
|
2015-01-01 14:56:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the subscriptions currently associated with this node as owner.
|
|
|
|
*
|
|
|
|
* @return List of {@link Subscription}
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2015-01-01 14:56:12 +01:00
|
|
|
* @see #getSubscriptionsAsOwner(List, Collection)
|
|
|
|
* @since 4.1
|
|
|
|
*/
|
|
|
|
public List<Subscription> getSubscriptionsAsOwner() throws NoResponseException, XMPPErrorException,
|
2015-02-14 09:43:44 +01:00
|
|
|
NotConnectedException, InterruptedException {
|
2015-01-01 14:56:12 +01:00
|
|
|
return getSubscriptionsAsOwner(null, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the subscriptions currently associated with this node as owner.
|
|
|
|
* <p>
|
|
|
|
* Unlike {@link #getSubscriptions(List, Collection)}, which only retrieves the subscriptions of the current entity
|
|
|
|
* ("user"), this method returns a list of <b>all</b> subscriptions. This requires the entity to have the sufficient
|
|
|
|
* privileges to manage subscriptions.
|
|
|
|
* </p>
|
|
|
|
* <p>
|
|
|
|
* {@code additionalExtensions} can be used e.g. to add a "Result Set Management" extension.
|
2018-03-31 14:17:30 +02:00
|
|
|
* {@code returnedExtensions} will be filled with the stanza extensions found in the answer.
|
2015-01-01 14:56:12 +01:00
|
|
|
* </p>
|
|
|
|
*
|
2019-08-30 12:08:30 +02:00
|
|
|
* @param additionalExtensions TODO javadoc me please
|
2018-03-31 14:17:30 +02:00
|
|
|
* @param returnedExtensions a collection that will be filled with the returned stanza extensions
|
2015-01-01 14:56:12 +01:00
|
|
|
* @return List of {@link Subscription}
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2015-01-01 14:56:12 +01:00
|
|
|
* @see <a href="http://www.xmpp.org/extensions/xep-0060.html#owner-subscriptions-retrieve">XEP-60 § 8.8.1 -
|
|
|
|
* Retrieve Subscriptions List</a>
|
|
|
|
* @since 4.1
|
|
|
|
*/
|
2015-02-26 18:41:17 +01:00
|
|
|
public List<Subscription> getSubscriptionsAsOwner(List<ExtensionElement> additionalExtensions,
|
|
|
|
Collection<ExtensionElement> returnedExtensions) throws NoResponseException, XMPPErrorException,
|
2015-02-14 09:43:44 +01:00
|
|
|
NotConnectedException, InterruptedException {
|
2018-04-19 11:05:43 +02:00
|
|
|
return getSubscriptions(SubscriptionsNamespace.owner, additionalExtensions, returnedExtensions);
|
2015-01-01 14:56:12 +01:00
|
|
|
}
|
|
|
|
|
2018-04-19 11:05:43 +02:00
|
|
|
private List<Subscription> getSubscriptions(SubscriptionsNamespace subscriptionsNamespace, List<ExtensionElement> additionalExtensions,
|
|
|
|
Collection<ExtensionElement> returnedExtensions)
|
2015-02-14 09:43:44 +01:00
|
|
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2018-04-19 11:05:43 +02:00
|
|
|
PubSubElementType pubSubElementType = subscriptionsNamespace.type;
|
|
|
|
|
|
|
|
PubSub pubSub = createPubsubPacket(Type.get, new NodeExtension(pubSubElementType, getId()));
|
2014-07-09 12:57:51 +02:00
|
|
|
if (additionalExtensions != null) {
|
2015-02-26 18:41:17 +01:00
|
|
|
for (ExtensionElement pe : additionalExtensions) {
|
2014-07-09 12:57:51 +02:00
|
|
|
pubSub.addExtension(pe);
|
|
|
|
}
|
|
|
|
}
|
2015-01-01 15:11:21 +01:00
|
|
|
PubSub reply = sendPubsubPacket(pubSub);
|
2014-07-09 12:57:51 +02:00
|
|
|
if (returnedExtensions != null) {
|
|
|
|
returnedExtensions.addAll(reply.getExtensions());
|
|
|
|
}
|
2018-04-19 11:05:43 +02:00
|
|
|
SubscriptionsExtension subElem = reply.getExtension(pubSubElementType);
|
2014-07-09 12:57:51 +02:00
|
|
|
return subElem.getSubscriptions();
|
|
|
|
}
|
|
|
|
|
2018-03-20 11:49:32 +01:00
|
|
|
/**
|
|
|
|
* Modify the subscriptions for this PubSub node as owner.
|
|
|
|
* <p>
|
|
|
|
* Note that the subscriptions are _not_ checked against the existing subscriptions
|
|
|
|
* since these are not cached (and indeed could change asynchronously)
|
|
|
|
* </p>
|
|
|
|
*
|
|
|
|
* @param changedSubs subscriptions that have changed
|
|
|
|
* @return <code>null</code> or a PubSub stanza with additional information on success.
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2018-03-20 11:49:32 +01:00
|
|
|
* @see <a href="https://xmpp.org/extensions/xep-0060.html#owner-subscriptions-modify">XEP-60 § 8.8.2 Modify Subscriptions</a>
|
|
|
|
* @since 4.3
|
|
|
|
*/
|
|
|
|
public PubSub modifySubscriptionsAsOwner(List<Subscription> changedSubs)
|
|
|
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
|
|
|
|
|
|
|
PubSub pubSub = createPubsubPacket(Type.set,
|
2018-04-19 11:05:43 +02:00
|
|
|
new SubscriptionsExtension(SubscriptionsNamespace.owner, getId(), changedSubs));
|
2018-03-20 11:49:32 +01:00
|
|
|
return sendPubsubPacket(pubSub);
|
|
|
|
}
|
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
/**
|
|
|
|
* Get the affiliations of this node.
|
|
|
|
*
|
|
|
|
* @return List of {@link Affiliation}
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2017-02-07 22:02:40 +01:00
|
|
|
*/
|
2014-07-09 12:57:51 +02:00
|
|
|
public List<Affiliation> getAffiliations() throws NoResponseException, XMPPErrorException,
|
2015-02-14 09:43:44 +01:00
|
|
|
NotConnectedException, InterruptedException {
|
2014-07-09 12:57:51 +02:00
|
|
|
return getAffiliations(null, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the affiliations of this node.
|
|
|
|
* <p>
|
|
|
|
* {@code additionalExtensions} can be used e.g. to add a "Result Set Management" extension.
|
2018-03-31 14:17:30 +02:00
|
|
|
* {@code returnedExtensions} will be filled with the stanza extensions found in the answer.
|
2014-07-09 12:57:51 +02:00
|
|
|
* </p>
|
|
|
|
*
|
|
|
|
* @param additionalExtensions additional {@code PacketExtensions} add to the request
|
|
|
|
* @param returnedExtensions a collection that will be filled with the returned packet
|
|
|
|
* extensions
|
|
|
|
* @return List of {@link Affiliation}
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2014-07-09 12:57:51 +02:00
|
|
|
*/
|
2015-02-26 18:41:17 +01:00
|
|
|
public List<Affiliation> getAffiliations(List<ExtensionElement> additionalExtensions, Collection<ExtensionElement> returnedExtensions)
|
2015-02-14 09:43:44 +01:00
|
|
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2015-03-04 22:42:36 +01:00
|
|
|
|
2018-04-19 11:05:43 +02:00
|
|
|
return getAffiliations(AffiliationNamespace.basic, additionalExtensions, returnedExtensions);
|
2015-06-06 11:14:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the affiliation list for this node as owner.
|
|
|
|
*
|
|
|
|
* @return list of entities whose affiliation is not 'none'.
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2015-06-06 11:14:26 +02:00
|
|
|
* @see #getAffiliations(List, Collection)
|
|
|
|
* @since 4.2
|
|
|
|
*/
|
|
|
|
public List<Affiliation> getAffiliationsAsOwner()
|
|
|
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
|
|
|
|
|
|
|
return getAffiliationsAsOwner(null, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the affiliation list for this node as owner.
|
|
|
|
* <p>
|
2017-12-13 23:10:11 +01:00
|
|
|
* Note that this is an <b>optional</b> PubSub feature ('pubsub#modify-affiliations').
|
2015-06-06 11:14:26 +02:00
|
|
|
* </p>
|
|
|
|
*
|
|
|
|
* @param additionalExtensions optional additional extension elements add to the request.
|
|
|
|
* @param returnedExtensions an optional collection that will be filled with the returned
|
|
|
|
* extension elements.
|
|
|
|
* @return list of entities whose affiliation is not 'none'.
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2015-06-06 11:14:26 +02:00
|
|
|
* @see <a href="http://www.xmpp.org/extensions/xep-0060.html#owner-affiliations-retrieve">XEP-60 § 8.9.1 Retrieve Affiliations List</a>
|
|
|
|
* @since 4.2
|
|
|
|
*/
|
|
|
|
public List<Affiliation> getAffiliationsAsOwner(List<ExtensionElement> additionalExtensions, Collection<ExtensionElement> returnedExtensions)
|
|
|
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
|
|
|
|
2018-04-19 11:05:43 +02:00
|
|
|
return getAffiliations(AffiliationNamespace.owner, additionalExtensions, returnedExtensions);
|
2015-06-06 11:14:26 +02:00
|
|
|
}
|
|
|
|
|
2018-04-19 11:05:43 +02:00
|
|
|
private List<Affiliation> getAffiliations(AffiliationNamespace affiliationsNamespace, List<ExtensionElement> additionalExtensions,
|
2015-06-06 11:14:26 +02:00
|
|
|
Collection<ExtensionElement> returnedExtensions) throws NoResponseException, XMPPErrorException,
|
|
|
|
NotConnectedException, InterruptedException {
|
2018-04-19 11:05:43 +02:00
|
|
|
PubSubElementType pubSubElementType = affiliationsNamespace.type;
|
2015-06-06 11:14:26 +02:00
|
|
|
|
2018-04-19 11:05:43 +02:00
|
|
|
PubSub pubSub = createPubsubPacket(Type.get, new NodeExtension(pubSubElementType, getId()));
|
2014-07-09 12:57:51 +02:00
|
|
|
if (additionalExtensions != null) {
|
2015-02-26 18:41:17 +01:00
|
|
|
for (ExtensionElement pe : additionalExtensions) {
|
2014-07-09 12:57:51 +02:00
|
|
|
pubSub.addExtension(pe);
|
|
|
|
}
|
|
|
|
}
|
2015-01-01 15:11:21 +01:00
|
|
|
PubSub reply = sendPubsubPacket(pubSub);
|
2014-07-09 12:57:51 +02:00
|
|
|
if (returnedExtensions != null) {
|
|
|
|
returnedExtensions.addAll(reply.getExtensions());
|
|
|
|
}
|
2018-04-19 11:05:43 +02:00
|
|
|
AffiliationsExtension affilElem = reply.getExtension(pubSubElementType);
|
2014-07-09 12:57:51 +02:00
|
|
|
return affilElem.getAffiliations();
|
|
|
|
}
|
|
|
|
|
2015-06-06 11:14:26 +02:00
|
|
|
/**
|
|
|
|
* Modify the affiliations for this PubSub node as owner. The {@link Affiliation}s given must be created with the
|
|
|
|
* {@link Affiliation#Affiliation(org.jxmpp.jid.BareJid, Affiliation.Type)} constructor.
|
|
|
|
* <p>
|
2017-12-13 23:10:11 +01:00
|
|
|
* Note that this is an <b>optional</b> PubSub feature ('pubsub#modify-affiliations').
|
2015-06-06 11:14:26 +02:00
|
|
|
* </p>
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2019-08-30 12:08:30 +02:00
|
|
|
* @param affiliations TODO javadoc me please
|
2015-06-06 11:14:26 +02:00
|
|
|
* @return <code>null</code> or a PubSub stanza with additional information on success.
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2015-06-06 11:14:26 +02:00
|
|
|
* @see <a href="http://www.xmpp.org/extensions/xep-0060.html#owner-affiliations-modify">XEP-60 § 8.9.2 Modify Affiliation</a>
|
|
|
|
* @since 4.2
|
|
|
|
*/
|
|
|
|
public PubSub modifyAffiliationAsOwner(List<Affiliation> affiliations) throws NoResponseException,
|
|
|
|
XMPPErrorException, NotConnectedException, InterruptedException {
|
|
|
|
for (Affiliation affiliation : affiliations) {
|
2018-04-19 11:05:43 +02:00
|
|
|
if (affiliation.getPubSubNamespace() != PubSubNamespace.owner) {
|
2015-06-06 11:14:26 +02:00
|
|
|
throw new IllegalArgumentException("Must use Affiliation(BareJid, Type) affiliations");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-19 11:05:43 +02:00
|
|
|
PubSub pubSub = createPubsubPacket(Type.set, new AffiliationsExtension(AffiliationNamespace.owner, affiliations, getId()));
|
2015-06-06 11:14:26 +02:00
|
|
|
return sendPubsubPacket(pubSub);
|
|
|
|
}
|
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
/**
|
|
|
|
* The user subscribes to the node using the supplied jid. The
|
|
|
|
* bare jid portion of this one must match the jid for the connection.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
|
|
|
* Please note that the {@link Subscription.State} should be checked
|
2017-02-07 22:02:40 +01:00
|
|
|
* on return since more actions may be required by the caller.
|
2018-05-09 23:06:12 +02:00
|
|
|
* {@link Subscription.State#pending} - The owner must approve the subscription
|
2017-02-07 22:02:40 +01:00
|
|
|
* request before messages will be received.
|
2018-05-09 23:06:12 +02:00
|
|
|
* {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true,
|
2017-02-07 22:02:40 +01:00
|
|
|
* 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
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2017-02-07 22:02:40 +01:00
|
|
|
*/
|
2019-07-05 11:24:02 +02:00
|
|
|
public Subscription subscribe(Jid jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2017-02-07 22:02:40 +01:00
|
|
|
PubSub pubSub = createPubsubPacket(Type.set, new SubscribeExtension(jid, getId()));
|
|
|
|
PubSub reply = sendPubsubPacket(pubSub);
|
|
|
|
return reply.getExtension(PubSubElementType.SUBSCRIPTION);
|
|
|
|
}
|
|
|
|
|
2019-07-05 11:24:02 +02:00
|
|
|
/**
|
|
|
|
* 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 jidString The jid to subscribe as.
|
|
|
|
* @return The subscription
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2019-07-05 11:24:02 +02:00
|
|
|
* @throws IllegalArgumentException if the provided string is not a valid JID.
|
|
|
|
* @deprecated use {@link #subscribe(Jid)} instead.
|
|
|
|
*/
|
|
|
|
@Deprecated
|
|
|
|
// TODO: Remove in Smack 4.5.
|
|
|
|
public Subscription subscribe(String jidString) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
|
|
|
Jid jid;
|
|
|
|
try {
|
|
|
|
jid = JidCreate.from(jidString);
|
|
|
|
} catch (XmppStringprepException e) {
|
|
|
|
throw new IllegalArgumentException(e);
|
|
|
|
}
|
|
|
|
return subscribe(jid);
|
|
|
|
}
|
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
/**
|
|
|
|
* The user subscribes to the node using the supplied jid and subscription
|
2018-05-09 23:06:12 +02:00
|
|
|
* options. The bare jid portion of this one must match the jid for the
|
2017-02-07 22:02:40 +01:00
|
|
|
* connection.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
|
|
|
* Please note that the {@link Subscription.State} should be checked
|
2017-02-07 22:02:40 +01:00
|
|
|
* on return since more actions may be required by the caller.
|
2018-05-09 23:06:12 +02:00
|
|
|
* {@link Subscription.State#pending} - The owner must approve the subscription
|
2017-02-07 22:02:40 +01:00
|
|
|
* request before messages will be received.
|
2018-05-09 23:06:12 +02:00
|
|
|
* {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true,
|
2017-02-07 22:02:40 +01:00
|
|
|
* 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.
|
2017-12-23 20:21:19 +01:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @param jid The jid to subscribe as.
|
2019-08-30 12:08:30 +02:00
|
|
|
* @param subForm TODO javadoc me please
|
2017-12-23 20:21:19 +01:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @return The subscription
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2017-02-07 22:02:40 +01:00
|
|
|
*/
|
2020-05-13 20:14:41 +02:00
|
|
|
public Subscription subscribe(Jid jid, FillableSubscribeForm subForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
|
|
|
DataForm submitForm = subForm.getDataFormToSubmit();
|
2017-02-07 22:02:40 +01:00
|
|
|
PubSub request = createPubsubPacket(Type.set, new SubscribeExtension(jid, getId()));
|
2020-05-13 20:14:41 +02:00
|
|
|
request.addExtension(new FormNode(FormNodeType.OPTIONS, submitForm));
|
2017-02-07 22:02:40 +01:00
|
|
|
PubSub reply = sendPubsubPacket(request);
|
|
|
|
return reply.getExtension(PubSubElementType.SUBSCRIPTION);
|
|
|
|
}
|
|
|
|
|
2019-07-05 11:24:02 +02:00
|
|
|
/**
|
|
|
|
* 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 jidString The jid to subscribe as.
|
2019-08-30 12:08:30 +02:00
|
|
|
* @param subForm TODO javadoc me please
|
2019-07-05 11:24:02 +02:00
|
|
|
*
|
|
|
|
* @return The subscription
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2019-07-05 11:24:02 +02:00
|
|
|
* @throws IllegalArgumentException if the provided string is not a valid JID.
|
2020-05-13 20:14:41 +02:00
|
|
|
* @deprecated use {@link #subscribe(Jid, FillableSubscribeForm)} instead.
|
2019-07-05 11:24:02 +02:00
|
|
|
*/
|
|
|
|
@Deprecated
|
|
|
|
// TODO: Remove in Smack 4.5.
|
2020-05-13 20:14:41 +02:00
|
|
|
public Subscription subscribe(String jidString, FillableSubscribeForm subForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2019-07-05 11:24:02 +02:00
|
|
|
Jid jid;
|
|
|
|
try {
|
|
|
|
jid = JidCreate.from(jidString);
|
|
|
|
} catch (XmppStringprepException e) {
|
|
|
|
throw new IllegalArgumentException(e);
|
|
|
|
}
|
|
|
|
return subscribe(jid, subForm);
|
|
|
|
}
|
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
/**
|
2018-05-09 23:06:12 +02:00
|
|
|
* Remove the subscription related to the specified JID. This will only
|
2017-02-07 22:02:40 +01:00
|
|
|
* work if there is only 1 subscription. If there are multiple subscriptions,
|
|
|
|
* use {@link #unsubscribe(String, String)}.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @param jid The JID used to subscribe to the node
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public void unsubscribe(String jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2017-02-07 22:02:40 +01:00
|
|
|
unsubscribe(jid, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove the specific subscription related to the specified JID.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @param jid The JID used to subscribe to the node
|
|
|
|
* @param subscriptionId The id of the subscription being removed
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2017-02-07 22:02:40 +01:00
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public void unsubscribe(String jid, String subscriptionId) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2017-02-07 22:02:40 +01:00
|
|
|
sendPubsubPacket(createPubsubPacket(Type.set, new UnsubscribeExtension(jid, getId(), subscriptionId)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a SubscribeForm for subscriptions, from which you can create an answer form to be submitted
|
2020-05-13 20:14:41 +02:00
|
|
|
* via the {@link #sendConfigurationForm(FillableConfigureForm)}.
|
2017-12-23 20:21:19 +01:00
|
|
|
*
|
2019-08-30 12:08:30 +02:00
|
|
|
* @param jid TODO javadoc me please
|
2017-12-23 20:21:19 +01:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @return A subscription options form
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2017-02-07 22:02:40 +01:00
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public SubscribeForm getSubscriptionOptions(String jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2017-02-07 22:02:40 +01:00
|
|
|
return getSubscriptionOptions(jid, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the options for configuring the specified subscription.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @param jid JID the subscription is registered under
|
|
|
|
* @param subscriptionId The subscription id
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @return The subscription option form
|
2019-08-30 12:08:30 +02:00
|
|
|
* @throws XMPPErrorException if there was an XMPP error returned.
|
|
|
|
* @throws NoResponseException if there was no response from the remote entity.
|
|
|
|
* @throws NotConnectedException if the XMPP connection is not connected.
|
|
|
|
* @throws InterruptedException if the calling thread was interrupted.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public SubscribeForm getSubscriptionOptions(String jid, String subscriptionId) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2017-02-07 22:02:40 +01:00
|
|
|
PubSub packet = sendPubsubPacket(createPubsubPacket(Type.get, new OptionsExtension(jid, getId(), subscriptionId)));
|
|
|
|
FormNode ext = packet.getExtension(PubSubElementType.OPTIONS);
|
|
|
|
return new SubscribeForm(ext.getForm());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-05-09 23:06:12 +02:00
|
|
|
* Register a listener for item publication events. This
|
|
|
|
* listener will get called whenever an item is published to
|
2017-02-07 22:02:40 +01:00
|
|
|
* this node.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @param listener The handler for the event
|
|
|
|
*/
|
|
|
|
@SuppressWarnings("unchecked")
|
2018-04-06 10:21:46 +02:00
|
|
|
public void addItemEventListener(@SuppressWarnings("rawtypes") ItemEventListener listener) {
|
2018-05-09 23:06:12 +02:00
|
|
|
StanzaListener conListener = new ItemEventTranslator(listener);
|
2017-02-07 22:02:40 +01:00
|
|
|
itemEventToListenerMap.put(listener, conListener);
|
|
|
|
pubSubManager.getConnection().addSyncStanzaListener(conListener, new EventContentFilter(EventElementType.items.toString(), "item"));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unregister a listener for publication events.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @param listener The handler to unregister
|
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public void removeItemEventListener(@SuppressWarnings("rawtypes") ItemEventListener listener) {
|
2017-02-07 22:02:40 +01:00
|
|
|
StanzaListener conListener = itemEventToListenerMap.remove(listener);
|
|
|
|
|
|
|
|
if (conListener != null)
|
|
|
|
pubSubManager.getConnection().removeSyncStanzaListener(conListener);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Register a listener for configuration events. This listener
|
|
|
|
* will get called whenever the node's configuration changes.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @param listener The handler for the event
|
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public void addConfigurationListener(NodeConfigListener listener) {
|
2018-05-09 23:06:12 +02:00
|
|
|
StanzaListener conListener = new NodeConfigTranslator(listener);
|
2017-02-07 22:02:40 +01:00
|
|
|
configEventToListenerMap.put(listener, conListener);
|
|
|
|
pubSubManager.getConnection().addSyncStanzaListener(conListener, new EventContentFilter(EventElementType.configuration.toString()));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unregister a listener for configuration events.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @param listener The handler to unregister
|
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public void removeConfigurationListener(NodeConfigListener listener) {
|
2017-02-07 22:02:40 +01:00
|
|
|
StanzaListener conListener = configEventToListenerMap .remove(listener);
|
|
|
|
|
|
|
|
if (conListener != null)
|
|
|
|
pubSubManager.getConnection().removeSyncStanzaListener(conListener);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Register an listener for item delete events. This listener
|
|
|
|
* gets called whenever an item is deleted from the node.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @param listener The handler for the event
|
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public void addItemDeleteListener(ItemDeleteListener listener) {
|
2018-05-09 23:06:12 +02:00
|
|
|
StanzaListener delListener = new ItemDeleteTranslator(listener);
|
2017-02-07 22:02:40 +01:00
|
|
|
itemDeleteToListenerMap.put(listener, delListener);
|
|
|
|
EventContentFilter deleteItem = new EventContentFilter(EventElementType.items.toString(), "retract");
|
|
|
|
EventContentFilter purge = new EventContentFilter(EventElementType.purge.toString());
|
|
|
|
|
2018-04-08 21:21:50 +02:00
|
|
|
// TODO: Use AsyncButOrdered (with Node as Key?)
|
2017-02-07 22:02:40 +01:00
|
|
|
pubSubManager.getConnection().addSyncStanzaListener(delListener, new OrFilter(deleteItem, purge));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unregister a listener for item delete events.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @param listener The handler to unregister
|
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public void removeItemDeleteListener(ItemDeleteListener listener) {
|
2017-02-07 22:02:40 +01:00
|
|
|
StanzaListener conListener = itemDeleteToListenerMap .remove(listener);
|
|
|
|
|
|
|
|
if (conListener != null)
|
|
|
|
pubSubManager.getConnection().removeSyncStanzaListener(conListener);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2018-04-06 10:21:46 +02:00
|
|
|
public String toString() {
|
2017-02-07 22:02:40 +01:00
|
|
|
return super.toString() + " " + getClass().getName() + " id: " + id;
|
|
|
|
}
|
|
|
|
|
2018-04-19 11:05:43 +02:00
|
|
|
protected PubSub createPubsubPacket(Type type, NodeExtension ext) {
|
|
|
|
return PubSub.createPubsubPacket(pubSubManager.getServiceJid(), type, ext);
|
2017-02-07 22:02:40 +01:00
|
|
|
}
|
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
protected PubSub sendPubsubPacket(PubSub packet) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
2017-02-07 22:02:40 +01:00
|
|
|
return pubSubManager.sendPubsubPacket(packet);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
private static List<String> getSubscriptionIds(Stanza packet) {
|
2020-04-05 22:10:05 +02:00
|
|
|
HeadersExtension headers = packet.getExtension(HeadersExtension.class);
|
2017-02-07 22:02:40 +01:00
|
|
|
List<String> values = null;
|
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
if (headers != null) {
|
2017-12-13 23:10:11 +01:00
|
|
|
values = new ArrayList<>(headers.getHeaders().size());
|
2017-02-07 22:02:40 +01:00
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
for (Header header : headers.getHeaders()) {
|
2017-02-07 22:02:40 +01:00
|
|
|
values.add(header.getValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-05-09 23:06:12 +02:00
|
|
|
* This class translates low level item publication events into api level objects for
|
2017-02-07 22:02:40 +01:00
|
|
|
* user consumption.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @author Robin Collier
|
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public static class ItemEventTranslator implements StanzaListener {
|
2017-02-07 22:02:40 +01:00
|
|
|
@SuppressWarnings("rawtypes")
|
2017-12-13 23:10:11 +01:00
|
|
|
private final ItemEventListener listener;
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
public ItemEventTranslator(@SuppressWarnings("rawtypes") ItemEventListener eventListener) {
|
2017-02-07 22:02:40 +01:00
|
|
|
listener = eventListener;
|
|
|
|
}
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2017-02-11 16:16:41 +01:00
|
|
|
@Override
|
2017-02-07 22:02:40 +01:00
|
|
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
2018-04-06 10:21:46 +02:00
|
|
|
public void processStanza(Stanza packet) {
|
2020-04-12 12:09:04 +02:00
|
|
|
EventElement event = (EventElement) packet.getExtensionElement("event", PubSubNamespace.event.getXmlns());
|
2017-05-23 16:45:04 +02:00
|
|
|
ItemsExtension itemsElem = (ItemsExtension) event.getEvent();
|
2015-03-23 09:27:15 +01:00
|
|
|
ItemPublishEvent eventItems = new ItemPublishEvent(itemsElem.getNode(), itemsElem.getItems(), getSubscriptionIds(packet), DelayInformationManager.getDelayTimestamp(packet));
|
2018-04-08 21:21:50 +02:00
|
|
|
// TODO: Use AsyncButOrdered (with Node as Key?)
|
2017-02-07 22:02:40 +01:00
|
|
|
listener.handlePublishedItems(eventItems);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-05-09 23:06:12 +02:00
|
|
|
* This class translates low level item deletion events into api level objects for
|
2017-02-07 22:02:40 +01:00
|
|
|
* user consumption.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @author Robin Collier
|
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public static class ItemDeleteTranslator implements StanzaListener {
|
2017-12-13 23:10:11 +01:00
|
|
|
private final ItemDeleteListener listener;
|
2017-02-07 22:02:40 +01:00
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
public ItemDeleteTranslator(ItemDeleteListener eventListener) {
|
2017-02-07 22:02:40 +01:00
|
|
|
listener = eventListener;
|
|
|
|
}
|
|
|
|
|
2017-02-11 16:16:41 +01:00
|
|
|
@Override
|
2018-04-06 10:21:46 +02:00
|
|
|
public void processStanza(Stanza packet) {
|
2015-03-18 21:51:25 +01:00
|
|
|
// CHECKSTYLE:OFF
|
2020-04-12 12:09:04 +02:00
|
|
|
EventElement event = (EventElement) packet.getExtensionElement("event", PubSubNamespace.event.getXmlns());
|
2017-02-07 22:02:40 +01:00
|
|
|
|
|
|
|
List<ExtensionElement> extList = event.getExtensions();
|
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
if (extList.get(0).getElementName().equals(PubSubElementType.PURGE_EVENT.getElementName())) {
|
2017-02-07 22:02:40 +01:00
|
|
|
listener.handlePurge();
|
|
|
|
}
|
2018-04-06 10:21:46 +02:00
|
|
|
else {
|
2017-02-07 22:02:40 +01:00
|
|
|
ItemsExtension itemsElem = (ItemsExtension)event.getEvent();
|
|
|
|
@SuppressWarnings("unchecked")
|
2014-04-09 08:26:28 +02:00
|
|
|
Collection<RetractItem> pubItems = (Collection<RetractItem>) itemsElem.getItems();
|
2017-12-13 23:10:11 +01:00
|
|
|
List<String> items = new ArrayList<>(pubItems.size());
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
for (RetractItem item : pubItems) {
|
2017-02-07 22:02:40 +01:00
|
|
|
items.add(item.getId());
|
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
ItemDeleteEvent eventItems = new ItemDeleteEvent(itemsElem.getNode(), items, getSubscriptionIds(packet));
|
|
|
|
listener.handleDeletedItems(eventItems);
|
|
|
|
}
|
2015-03-18 21:51:25 +01:00
|
|
|
// CHECKSTYLE:ON
|
2017-02-07 22:02:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-05-09 23:06:12 +02:00
|
|
|
* This class translates low level node configuration events into api level objects for
|
2017-02-07 22:02:40 +01:00
|
|
|
* user consumption.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @author Robin Collier
|
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
public static class NodeConfigTranslator implements StanzaListener {
|
2017-12-13 23:10:11 +01:00
|
|
|
private final NodeConfigListener listener;
|
2017-02-07 22:02:40 +01:00
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
public NodeConfigTranslator(NodeConfigListener eventListener) {
|
2017-02-07 22:02:40 +01:00
|
|
|
listener = eventListener;
|
|
|
|
}
|
|
|
|
|
2017-02-11 16:16:41 +01:00
|
|
|
@Override
|
2018-04-06 10:21:46 +02:00
|
|
|
public void processStanza(Stanza packet) {
|
2020-04-12 12:09:04 +02:00
|
|
|
EventElement event = (EventElement) packet.getExtensionElement("event", PubSubNamespace.event.getXmlns());
|
2017-05-23 16:45:04 +02:00
|
|
|
ConfigurationEvent config = (ConfigurationEvent) event.getEvent();
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2018-04-08 21:21:50 +02:00
|
|
|
// TODO: Use AsyncButOrdered (with Node as Key?)
|
2017-02-07 22:02:40 +01:00
|
|
|
listener.handleNodeConfiguration(config);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-05-09 23:06:12 +02:00
|
|
|
* Filter for {@link StanzaListener} to filter out events not specific to the
|
2017-02-07 22:02:40 +01:00
|
|
|
* event type expected for this node.
|
2018-05-09 23:06:12 +02:00
|
|
|
*
|
2017-02-07 22:02:40 +01:00
|
|
|
* @author Robin Collier
|
|
|
|
*/
|
2018-04-06 10:21:46 +02:00
|
|
|
class EventContentFilter extends FlexibleStanzaTypeFilter<Message> {
|
2015-12-06 22:49:48 +01:00
|
|
|
private final String firstElement;
|
|
|
|
private final String secondElement;
|
2015-12-06 06:08:02 +01:00
|
|
|
private final boolean allowEmpty;
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
EventContentFilter(String elementName) {
|
2015-12-06 22:49:48 +01:00
|
|
|
this(elementName, null);
|
2017-02-07 22:02:40 +01:00
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
EventContentFilter(String firstLevelElement, String secondLevelElement) {
|
2017-12-13 23:10:11 +01:00
|
|
|
firstElement = firstLevelElement;
|
2017-02-07 22:02:40 +01:00
|
|
|
secondElement = secondLevelElement;
|
2015-12-06 06:08:02 +01:00
|
|
|
allowEmpty = firstElement.equals(EventElementType.items.toString())
|
|
|
|
&& "item".equals(secondLevelElement);
|
2017-02-07 22:02:40 +01:00
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2017-02-11 16:16:41 +01:00
|
|
|
@Override
|
2015-12-06 22:48:22 +01:00
|
|
|
public boolean acceptSpecific(Message message) {
|
|
|
|
EventElement event = EventElement.from(message);
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
if (event == null)
|
|
|
|
return false;
|
2014-02-17 23:58:40 +01:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
NodeExtension embedEvent = event.getEvent();
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
if (embedEvent == null)
|
|
|
|
return false;
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
if (embedEvent.getElementName().equals(firstElement)) {
|
2017-02-07 22:02:40 +01:00
|
|
|
if (!embedEvent.getNode().equals(getId()))
|
|
|
|
return false;
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
if (secondElement == null)
|
|
|
|
return true;
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2018-04-06 10:21:46 +02:00
|
|
|
if (embedEvent instanceof EmbeddedPacketExtension) {
|
2017-05-23 16:45:04 +02:00
|
|
|
List<ExtensionElement> secondLevelList = ((EmbeddedPacketExtension) embedEvent).getExtensions();
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2015-12-06 06:08:02 +01:00
|
|
|
// XEP-0060 allows no elements on second level for notifications. See schema or
|
|
|
|
// for example § 4.3:
|
|
|
|
// "although event notifications MUST include an empty <items/> element;"
|
|
|
|
if (allowEmpty && secondLevelList.isEmpty()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
if (secondLevelList.size() > 0 && secondLevelList.get(0).getElementName().equals(secondElement))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2014-02-17 23:58:40 +01:00
|
|
|
}
|