From 33e5c37af80d4e1045fd161cc4775c56612b1b00 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 17 Aug 2015 08:16:49 +0200 Subject: [PATCH] Refactor PEP to use PubSub API. Fixes SMACK-416. --- .../filter/jidtype/AbstractJidTypeFilter.java | 89 ++++++++++ .../filter/jidtype/FromJidTypeFilter.java | 39 +++++ .../smack/filter/jidtype}/package-info.java | 4 +- .../jivesoftware/smackx/disco/Feature.java | 41 +++++ .../smackx/disco/ServiceDiscoveryManager.java | 34 +++- .../smackx/disco/packet/DiscoverInfo.java | 6 +- .../jivesoftware/smackx/pep/PEPListener.java | 11 +- .../jivesoftware/smackx/pep/PEPManager.java | 161 +++++++++--------- .../smackx/pep/packet/PEPEvent.java | 102 ----------- .../smackx/pep/packet/PEPItem.java | 89 ---------- .../smackx/pep/packet/PEPPubSub.java | 74 -------- .../smackx/pep/provider/PEPProvider.java | 84 --------- .../smackx/pubsub/EventElement.java | 30 +++- .../smackx/pubsub/PubSubFeature.java | 115 +++++++++++++ .../smackx/pubsub/PubSubManager.java | 13 +- .../pubsub/filter/EventExtensionFilter.java | 36 ++++ .../filter}/package-info.java | 4 +- 17 files changed, 479 insertions(+), 453 deletions(-) create mode 100644 smack-core/src/main/java/org/jivesoftware/smack/filter/jidtype/AbstractJidTypeFilter.java create mode 100644 smack-core/src/main/java/org/jivesoftware/smack/filter/jidtype/FromJidTypeFilter.java rename {smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet => smack-core/src/main/java/org/jivesoftware/smack/filter/jidtype}/package-info.java (86%) create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/disco/Feature.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/PEPEvent.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/PEPItem.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/PEPPubSub.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/pep/provider/PEPProvider.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubFeature.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/filter/EventExtensionFilter.java rename smack-extensions/src/main/java/org/jivesoftware/smackx/{pep/provider => pubsub/filter}/package-info.java (87%) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/jidtype/AbstractJidTypeFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/jidtype/AbstractJidTypeFilter.java new file mode 100644 index 000000000..13ea8972a --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/jidtype/AbstractJidTypeFilter.java @@ -0,0 +1,89 @@ +/** + * + * Copyright 2015 Florian Schmaus. + * + * 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.smack.filter.jidtype; + +import org.jivesoftware.smack.filter.StanzaFilter; +import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smack.util.Objects; +import org.jxmpp.jid.Jid; + +/** + * Base class for XMPP address type filters. + * + * @author Florian Schmaus + * + */ +public abstract class AbstractJidTypeFilter implements StanzaFilter { + + private final JidType jidType; + + protected AbstractJidTypeFilter(JidType jidType) { + this.jidType = Objects.requireNonNull(jidType, "jidType must not be null"); + } + + @Override + public boolean accept(Stanza stanza) { + Jid toMatch = getJidToMatchFrom(stanza); + if (toMatch == null) { + return false; + } + return jidType.isTypeOf(toMatch); + } + + protected abstract Jid getJidToMatchFrom(Stanza stanza); + + @Override + public final String toString() { + return getClass().getSimpleName() + ": " + jidType; + } + + public enum JidType { + BareJid, + DomainBareJid, + DomainFullJid, + DomainJid, + EntityBareJid, + EntityFullJid, + EntityJid, + FullJid, + ; + + public boolean isTypeOf(Jid jid) { + if (jid == null) { + return false; + } + switch (this) { + case BareJid: + return jid.hasNoResource(); + case DomainBareJid: + return jid.isDomainBareJid(); + case DomainFullJid: + return jid.isDomainFullJid(); + case EntityBareJid: + return jid.isEntityBareJid(); + case EntityFullJid: + return jid.isEntityFullJid(); + case EntityJid: + return jid.isEntityJid(); + case FullJid: + return jid.hasResource(); + default: + throw new IllegalStateException(); + } + } + } +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/jidtype/FromJidTypeFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/jidtype/FromJidTypeFilter.java new file mode 100644 index 000000000..97c82ba64 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/jidtype/FromJidTypeFilter.java @@ -0,0 +1,39 @@ +/** + * + * Copyright 2015 Florian Schmaus. + * + * 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.smack.filter.jidtype; + +import org.jivesoftware.smack.packet.Stanza; +import org.jxmpp.jid.Jid; + +/** + * Filter based on the 'from' XMPP address type. + * + * @author Florian Schmaus + * + */ +public class FromJidTypeFilter extends AbstractJidTypeFilter { + + public FromJidTypeFilter(JidType jidType) { + super(jidType); + } + + @Override + protected Jid getJidToMatchFrom(Stanza stanza) { + return stanza.getFrom(); + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/package-info.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/jidtype/package-info.java similarity index 86% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/package-info.java rename to smack-core/src/main/java/org/jivesoftware/smack/filter/jidtype/package-info.java index 253526c74..d3d2fe970 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/package-info.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/jidtype/package-info.java @@ -16,6 +16,6 @@ */ /** - * TODO describe me. + * Filter based on the type of an XMPP address. */ -package org.jivesoftware.smackx.pep.packet; +package org.jivesoftware.smack.filter.jidtype; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/Feature.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/Feature.java new file mode 100644 index 000000000..cb43bcee5 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/Feature.java @@ -0,0 +1,41 @@ +/** + * + * Copyright 2015 Florian Schmaus + * + * 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.disco; + +/** + * Utility class for Features. + * + * @author Florian Schmaus + * + */ +public class Feature { + + public enum Support { + optional, + recommended, + required, + ; + + public boolean isRequired() { + return this == required; + } + + public boolean isNotRequired() { + return !isRequired(); + } + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java index 84311b6d2..27b4ed1bf 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java @@ -41,6 +41,8 @@ import org.jxmpp.util.cache.Cache; import org.jxmpp.util.cache.ExpirationCache; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; @@ -659,9 +661,20 @@ public final class ServiceDiscoveryManager extends Manager { * @throws InterruptedException * @since 4.1 */ - public boolean serverSupportsFeature(String feature) throws NoResponseException, XMPPErrorException, + public boolean serverSupportsFeature(CharSequence feature) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { - return supportsFeature(connection().getXMPPServiceDomain(), feature); + return serverSupportsFeatures(feature); + } + + public boolean serverSupportsFeatures(CharSequence... features) throws NoResponseException, + XMPPErrorException, NotConnectedException, InterruptedException { + return serverSupportsFeatures(Arrays.asList(features)); + } + + public boolean serverSupportsFeatures(Collection features) + throws NoResponseException, XMPPErrorException, NotConnectedException, + InterruptedException { + return supportsFeatures(connection().getXMPPServiceDomain(), features); } /** @@ -675,9 +688,22 @@ public final class ServiceDiscoveryManager extends Manager { * @throws NotConnectedException * @throws InterruptedException */ - public boolean supportsFeature(Jid jid, String feature) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + public boolean supportsFeature(Jid jid, CharSequence feature) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + return supportsFeatures(jid, feature); + } + + public boolean supportsFeatures(Jid jid, CharSequence... features) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + return supportsFeatures(jid, Arrays.asList(features)); + } + + public boolean supportsFeatures(Jid jid, Collection features) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { DiscoverInfo result = discoverInfo(jid); - return result.containsFeature(feature); + for (CharSequence feature : features) { + if (!result.containsFeature(feature)) { + return false; + } + } + return true; } /** diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java index 360df83ff..1957d2392 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java @@ -209,7 +209,7 @@ public class DiscoverInfo extends IQ implements TypedCloneable { * @param feature the feature to check * @return true if the requestes feature has been discovered */ - public boolean containsFeature(String feature) { + public boolean containsFeature(CharSequence feature) { return features.contains(new Feature(feature)); } @@ -482,6 +482,10 @@ public class DiscoverInfo extends IQ implements TypedCloneable { this.variable = feature.variable; } + public Feature(CharSequence variable) { + this(variable.toString()); + } + /** * Creates a new feature offered by an XMPP entity or item. * diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/PEPListener.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/PEPListener.java index b53811847..e43059b95 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/PEPListener.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/PEPListener.java @@ -1,6 +1,6 @@ /** * - * Copyright 2003-2007 Jive Software. + * Copyright 2003-2007 Jive Software, 2015 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,9 @@ package org.jivesoftware.smackx.pep; -import org.jivesoftware.smackx.pep.packet.PEPEvent; -import org.jxmpp.jid.Jid; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smackx.pubsub.EventElement; +import org.jxmpp.jid.EntityBareJid; /** @@ -26,6 +27,7 @@ import org.jxmpp.jid.Jid; * A listener that is fired anytime a PEP event message is received. * * @author Jeff Williams + * @author Florian Schmaus */ public interface PEPListener { @@ -34,7 +36,8 @@ public interface PEPListener { * * @param from the user that sent the entries. * @param event the event contained in the message. + * @param message the message stanza containing the PEP event. */ - public void eventReceived(Jid from, PEPEvent event); + public void eventReceived(EntityBareJid from, EventElement event, Message message); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/PEPManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/PEPManager.java index d61a09ea6..a7574e154 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/PEPManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/PEPManager.java @@ -1,6 +1,6 @@ /** * - * Copyright 2003-2007 Jive Software. + * Copyright 2003-2007 Jive Software, 2015 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,21 +17,32 @@ package org.jivesoftware.smackx.pep; -import java.util.ArrayList; -import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.filter.StanzaExtensionFilter; +import org.jivesoftware.smack.XMPPException.XMPPErrorException; +import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.StanzaFilter; +import org.jivesoftware.smack.filter.jidtype.FromJidTypeFilter; +import org.jivesoftware.smack.filter.jidtype.AbstractJidTypeFilter.JidType; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Stanza; -import org.jivesoftware.smack.packet.IQ.Type; -import org.jivesoftware.smackx.pep.packet.PEPEvent; -import org.jivesoftware.smackx.pep.packet.PEPItem; -import org.jivesoftware.smackx.pep.packet.PEPPubSub; -import org.jxmpp.jid.Jid; +import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; +import org.jivesoftware.smackx.pubsub.EventElement; +import org.jivesoftware.smackx.pubsub.Item; +import org.jivesoftware.smackx.pubsub.LeafNode; +import org.jivesoftware.smackx.pubsub.PubSubFeature; +import org.jivesoftware.smackx.pubsub.PubSubManager; +import org.jivesoftware.smackx.pubsub.filter.EventExtensionFilter; +import org.jxmpp.jid.BareJid; +import org.jxmpp.jid.EntityBareJid; /** * @@ -44,38 +55,55 @@ import org.jxmpp.jid.Jid; *
  *   PEPManager pepManager = new PEPManager(smackConnection);
  *   pepManager.addPEPListener(new PEPListener() {
- *       public void eventReceived(String inFrom, PEPEvent inEvent) {
- *           LOGGER.debug("Event received: " + inEvent);
+ *       public void eventReceived(EntityBareJid from, EventElement event, Message message) {
+ *           LOGGER.debug("Event received: " + event);
  *       }
  *   });
- *
- *   PEPProvider pepProvider = new PEPProvider();
- *   pepProvider.registerPEPParserExtension("http://jabber.org/protocol/tune", new TuneProvider());
- *   ProviderManager.getInstance().addExtensionProvider("event", "http://jabber.org/protocol/pubsub#event", pepProvider);
- *   
- *   Tune tune = new Tune("jeff", "1", "CD", "My Title", "My Track");
- *   pepManager.publish(tune);
  * 
* * @author Jeff Williams + * @author Florian Schmaus */ -public class PEPManager { +public final class PEPManager extends Manager { - private List pepListeners = new ArrayList(); + private static final Map INSTANCES = new WeakHashMap<>(); - private XMPPConnection connection; + public static synchronized PEPManager getInstanceFor(XMPPConnection connection) { + PEPManager pepManager = INSTANCES.get(connection); + if (pepManager == null) { + pepManager = new PEPManager(connection); + INSTANCES.put(connection, pepManager); + } + return pepManager; + } - private StanzaFilter packetFilter = new StanzaExtensionFilter("event", "http://jabber.org/protocol/pubsub#event"); - private StanzaListener packetListener; + private static final StanzaFilter FROM_BARE_JID_WITH_EVENT_EXTENSION_FILTER = new AndFilter( + new FromJidTypeFilter(JidType.BareJid), + EventExtensionFilter.INSTANCE); + + private final Set pepListeners = new CopyOnWriteArraySet<>(); /** * Creates a new PEP exchange manager. * * @param connection an XMPPConnection which is used to send and receive messages. */ - public PEPManager(XMPPConnection connection) { - this.connection = connection; - init(); + private PEPManager(XMPPConnection connection) { + super(connection); + StanzaListener packetListener = new StanzaListener() { + public void processPacket(Stanza stanza) { + Message message = (Message) stanza; + EventElement event = EventElement.from(stanza); + assert(event != null); + EntityBareJid from = message.getFrom().asEntityBareJidIfPossible(); + assert(from != null); + for (PEPListener listener : pepListeners) { + listener.eventReceived(from, event, message); + } + } + }; + // TODO Add filter to check if from supports PubSub as per xep163 2 2.4 + connection.addSyncStanzaListener(packetListener, FROM_BARE_JID_WITH_EVENT_EXTENSION_FILTER); } /** @@ -84,12 +112,8 @@ public class PEPManager { * * @param pepListener a roster exchange listener. */ - public void addPEPListener(PEPListener pepListener) { - synchronized (pepListeners) { - if (!pepListeners.contains(pepListener)) { - pepListeners.add(pepListener); - } - } + public boolean addPEPListener(PEPListener pepListener) { + return pepListeners.add(pepListener); } /** @@ -97,63 +121,44 @@ public class PEPManager { * * @param pepListener a roster exchange listener. */ - public void removePEPListener(PEPListener pepListener) { - synchronized (pepListeners) { - pepListeners.remove(pepListener); - } + public boolean removePEPListener(PEPListener pepListener) { + return pepListeners.remove(pepListener); } /** * Publish an event. * * @param item the item to publish. - * @throws NotConnectedException - * @throws InterruptedException + * @param node the node to publish on. + * @throws NotConnectedException + * @throws InterruptedException + * @throws XMPPErrorException + * @throws NoResponseException */ - public void publish(PEPItem item) throws NotConnectedException, InterruptedException { - // Create a new message to publish the event. - PEPPubSub pubSub = new PEPPubSub(item); - pubSub.setType(Type.set); - //pubSub.setFrom(connection.getUser()); - - // Send the message that contains the roster - connection.sendStanza(pubSub); + public void publish(Item item, String node) throws NotConnectedException, InterruptedException, + NoResponseException, XMPPErrorException { + XMPPConnection connection = connection(); + PubSubManager pubSubManager = PubSubManager.getInstance(connection, connection.getUser().asEntityBareJid()); + LeafNode pubSubNode = pubSubManager.getNode(node); + pubSubNode.publish(item); } /** - * Fires roster exchange listeners. + * XEP-163 5. */ - private void firePEPListeners(Jid from, PEPEvent event) { - PEPListener[] listeners = null; - synchronized (pepListeners) { - listeners = new PEPListener[pepListeners.size()]; - pepListeners.toArray(listeners); - } - for (int i = 0; i < listeners.length; i++) { - listeners[i].eventReceived(from, event); - } - } + private static final PubSubFeature[] REQUIRED_FEATURES = new PubSubFeature[] { + // @formatter:off + PubSubFeature.auto_create, + PubSubFeature.auto_subscribe, + PubSubFeature.filtered_notifications, + // @formatter:on + }; - private void init() { - // Listens for all roster exchange packets and fire the roster exchange listeners. - packetListener = new StanzaListener() { - public void processPacket(Stanza packet) { - Message message = (Message) packet; - PEPEvent event = (PEPEvent) message.getExtension("event", "http://jabber.org/protocol/pubsub#event"); - // Fire event for roster exchange listeners - firePEPListeners(message.getFrom(), event); - } - }; - connection.addSyncStanzaListener(packetListener, packetFilter); - } - - public void destroy() { - if (connection != null) - connection.removeSyncStanzaListener(packetListener); - } - - protected void finalize() throws Throwable { - destroy(); - super.finalize(); + public boolean isSupported() throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException { + XMPPConnection connection = connection(); + ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection); + BareJid localBareJid = connection.getUser().asBareJid(); + return serviceDiscoveryManager.supportsFeatures(localBareJid, REQUIRED_FEATURES); } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/PEPEvent.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/PEPEvent.java deleted file mode 100644 index 19819d0e1..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/PEPEvent.java +++ /dev/null @@ -1,102 +0,0 @@ -/** - * - * Copyright 2003-2007 Jive Software. - * - * 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.pep.packet; - -import org.jivesoftware.smack.packet.ExtensionElement; - -/** - * Represents XMPP Personal Event Protocol packets.

- * - * The 'http://jabber.org/protocol/pubsub#event' namespace is used to publish personal events items from one client - * to subscribed clients (See XEP-163). - * - * @author Jeff Williams - */ -public class PEPEvent implements ExtensionElement { - - PEPItem item; - - /** - * Creates a new empty roster exchange package. - * - */ - public PEPEvent() { - super(); - } - - /** - * Creates a new empty roster exchange package. - * - */ - public PEPEvent(PEPItem item) { - super(); - - this.item = item; - } - - public void addPEPItem(PEPItem item) { - this.item = item; - } - - /** - * Returns the XML element name of the extension sub-packet root element. - * Always returns "x" - * - * @return the XML element name of the stanza(/packet) extension. - */ - public String getElementName() { - return "event"; - } - - /** - * Returns the XML namespace of the extension sub-packet root element. - * According the specification the namespace is always "jabber:x:roster" - * (which is not to be confused with the 'jabber:iq:roster' namespace - * - * @return the XML namespace of the stanza(/packet) extension. - */ - public String getNamespace() { - return "http://jabber.org/protocol/pubsub"; - } - - /** - * Returns the XML representation of a Personal Event Publish according the specification. - * - * Usually the XML representation will be inside of a Message XML representation like - * in the following example: - *

-     * <message id="MlIpV-4" to="gato1@gato.home" from="gato3@gato.home/Smack">
-     *     <subject>Any subject you want</subject>
-     *     <body>This message contains roster items.</body>
-     *     <x xmlns="jabber:x:roster">
-     *         <item jid="gato1@gato.home"/>
-     *         <item jid="gato2@gato.home"/>
-     *     </x>
-     * </message>
-     * 
- * - */ - public String toXML() { - StringBuilder buf = new StringBuilder(); - buf.append('<').append(getElementName()).append(" xmlns=\"").append(getNamespace()).append("\">"); - buf.append(item.toXML()); - buf.append("'); - return buf.toString(); - } - -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/PEPItem.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/PEPItem.java deleted file mode 100644 index 9f435a393..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/PEPItem.java +++ /dev/null @@ -1,89 +0,0 @@ -/** - * - * Copyright 2003-2007 Jive Software. - * - * 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.pep.packet; - -import org.jivesoftware.smack.packet.ExtensionElement; - -/** - * Represents XMPP Personal Event Protocol packets.

- * - * The 'http://jabber.org/protocol/pubsub#event' namespace is used to publish personal events items from one client - * to subscribed clients (See XEP-163). - * - * @author Jeff Williams - */ -public abstract class PEPItem implements ExtensionElement { - - String id; - public abstract String getNode(); - public abstract String getItemDetailsXML(); - - /** - * Creates a new PEPItem. - * - */ - public PEPItem(String id) { - super(); - this.id = id; - } - - /** - * Returns the XML element name of the extension sub-packet root element. - * Always returns "x" - * - * @return the XML element name of the stanza(/packet) extension. - */ - public String getElementName() { - return "item"; - } - - /** - * Returns the XML namespace of the extension sub-packet root element. - * - * @return the XML namespace of the stanza(/packet) extension. - */ - public String getNamespace() { - return "http://jabber.org/protocol/pubsub"; - } - - /** - * Returns the XML representation of a Personal Event Publish according the specification. - * - * Usually the XML representation will be inside of a Message XML representation like - * in the following example: - *

-     * <message id="MlIpV-4" to="gato1@gato.home" from="gato3@gato.home/Smack">
-     *     <subject>Any subject you want</subject>
-     *     <body>This message contains roster items.</body>
-     *     <x xmlns="jabber:x:roster">
-     *         <item jid="gato1@gato.home"/>
-     *         <item jid="gato2@gato.home"/>
-     *     </x>
-     * </message>
-     * 
- * - */ - public String toXML() { - StringBuilder buf = new StringBuilder(); - buf.append('<').append(getElementName()).append(" id=\"").append(id).append("\">"); - buf.append(getItemDetailsXML()); - buf.append("'); - return buf.toString(); - } - -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/PEPPubSub.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/PEPPubSub.java deleted file mode 100644 index 9b94e1bc3..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/packet/PEPPubSub.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * - * Copyright 2003-2007 Jive Software. - * - * 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.pep.packet; - -import org.jivesoftware.smack.packet.IQ; - -/** - * Represents XMPP PEP/XEP-163 pubsub packets.

- * - * The 'http://jabber.org/protocol/pubsub' namespace is used to publish personal events items from one client - * to subscribed clients (See XEP-163). - * - * @author Jeff Williams - */ -public class PEPPubSub extends IQ { - - public static final String ELEMENT = "pubsub"; - public static final String NAMESPACE = "http://jabber.org/protocol/pubsub"; - - private final PEPItem item; - - /** - * Creates a new PubSub. - * - */ - public PEPPubSub(PEPItem item) { - super(ELEMENT, NAMESPACE); - this.item = item; - } - - /** - * Returns the XML representation of a Personal Event Publish according the specification. - * - * Usually the XML representation will be inside of a Message XML representation like - * in the following example: - *

-     * <message id="MlIpV-4" to="gato1@gato.home" from="gato3@gato.home/Smack">
-     *     <subject>Any subject you want</subject>
-     *     <body>This message contains roster items.</body>
-     *     <x xmlns="jabber:x:roster">
-     *         <item jid="gato1@gato.home"/>
-     *         <item jid="gato2@gato.home"/>
-     *     </x>
-     * </message>
-     * 
- * - */ - @Override - protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder buf) { - buf.rightAngleBracket(); - - buf.openElement("publish").attribute("node", item.getNode()).rightAngleBracket(); - buf.append(item.toXML()); - buf.closeElement("publish"); - - return buf; - } - -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/provider/PEPProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/provider/PEPProvider.java deleted file mode 100644 index 3702b4a0c..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/provider/PEPProvider.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * - * Copyright 2003-2007 Jive Software. - * - * 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.pep.provider; - -import java.util.HashMap; -import java.util.Map; - -import org.jivesoftware.smack.packet.ExtensionElement; -import org.jivesoftware.smack.provider.ExtensionElementProvider; -import org.xmlpull.v1.XmlPullParser; - -/** - * - * The PEPProvider parses incoming PEPEvent packets. - * (XEP-163 has a weird asymmetric deal: outbound PEP are + and inbound are + . - * The provider only deals with inbound, and so it only deals with . - * - * Anyhoo... - * - * The way this works is that PEPxxx classes are generic and providers, and anyone who - * wants to publish/receive PEPs, such as , , etc., simply need to extend PEPItem and register (here) - * a PacketExtensionProvider that knows how to parse that PEPItem extension. - * - * @author Jeff Williams - */ -public class PEPProvider extends ExtensionElementProvider { - - private static final Map> nodeParsers = new HashMap>(); - - public static void registerPEPParserExtension(String node, ExtensionElementProvider pepItemParser) { - nodeParsers.put(node, pepItemParser); - } - - /** - * Parses a PEPEvent stanza(/packet) and extracts a PEPItem from it. - * (There is only one per .) - * - * @param parser the XML parser, positioned at the starting element of the extension. - * @return a PacketExtension. - * @throws Exception - */ - @Override - public ExtensionElement parse(XmlPullParser parser, int initialDepth) - throws Exception { - ExtensionElement pepItem = null; - boolean done = false; - while (!done) { - int eventType = parser.next(); - if (eventType == XmlPullParser.START_TAG) { - if (parser.getName().equals("event")) { - } else if (parser.getName().equals("items")) { - // Figure out the node for this event. - String node = parser.getAttributeValue("", "node"); - // Get the parser for this kind of node, and if found then parse the node. - ExtensionElementProvider nodeParser = nodeParsers.get(node); - if (nodeParser != null) { - pepItem = nodeParser.parse(parser); - } - } - } else if (eventType == XmlPullParser.END_TAG) { - if (parser.getName().equals("event")) { - done = true; - } - } - } - - return pepItem; - } -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/EventElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/EventElement.java index 3b5a20ef7..cca9c2ae2 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/EventElement.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/EventElement.java @@ -20,6 +20,8 @@ import java.util.Arrays; import java.util.List; import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace; /** @@ -32,6 +34,16 @@ import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace; */ public class EventElement implements EmbeddedPacketExtension { + /** + * The constant String "event". + */ + public static final String ELEMENT = "event"; + + /** + * The constant String "http://jabber.org/protocol/pubsub#event". + */ + public static final String NAMESPACE = PubSubNamespace.EVENT.getXmlns(); + private EventElementType type; private NodeExtension ext; @@ -66,12 +78,16 @@ public class EventElement implements EmbeddedPacketExtension return PubSubNamespace.EVENT.getXmlns(); } - public String toXML() - { - StringBuilder builder = new StringBuilder(""); + @Override + public XmlStringBuilder toXML() { + XmlStringBuilder xml = new XmlStringBuilder(this); + xml.rightAngleBracket(); + xml.append(ext.toXML()); + xml.closeElement(this); + return xml; + } - builder.append(ext.toXML()); - builder.append(""); - return builder.toString(); - } + public static EventElement from(Stanza stanza) { + return stanza.getExtension(ELEMENT, NAMESPACE); + } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubFeature.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubFeature.java new file mode 100644 index 000000000..6aae6ae95 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubFeature.java @@ -0,0 +1,115 @@ +/** + * + * Copyright 2015 Florian Schmaus + * + * 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 org.jivesoftware.smackx.disco.Feature; +import org.jivesoftware.smackx.disco.Feature.Support; +import org.jivesoftware.smackx.pubsub.packet.PubSub; + +/** + * The features a PubSub service may provides. Some are optional or recommended, while others are required. + * + * @author Florian Schmaus + * @see XEP-60 ยง 10 + * + */ +public enum PubSubFeature implements CharSequence { + + access_authorize(Support.optional), + access_open(Support.optional), + access_presence(Support.optional), + access_roster(Support.optional), + acccess_whitelist(Support.optional), + auto_create(Support.optional), + auto_subscribe(Support.recommended), + collections(Support.optional), + config_node(Support.recommended), + create_and_configure(Support.recommended), + create_nodes(Support.recommended), + delete_items(Support.recommended), + delete_nodes(Support.recommended), + get_pending(Support.optional), + item_ids(Support.recommended), + last_published(Support.recommended), + leased_subscription(Support.optional), + manage_subscriptions(Support.optional), + member_affiliation(Support.recommended), + meta_data(Support.recommended), + modify_affiliations(Support.optional), + multi_collection(Support.optional), + multi_subscribe(Support.optional), + outcast_affiliation(Support.recommended), + persistent_items(Support.recommended), + presence_notifications(Support.optional), + presence_subscribe(Support.recommended), + publish(Support.required), + publish_options(Support.optional), + publish_only_affiliation(Support.optional), + publisher_affiliation(Support.recommended), + purge_nodes(Support.optional), + retract_items(Support.optional), + retrieve_affiliations(Support.recommended), + retrieve_default(Support.recommended), + retrieve_default_sub(Support.optional), + retrieve_items(Support.recommended), + retrieve_subscriptions(Support.recommended), + subscribe(Support.required), + subscription_options(Support.optional), + subscriptions_notifications(Support.optional), + instant_nodes(Support.recommended), + filtered_notifications(Support.recommended), + ; + + private final String feature; + private final String qualifiedFeature; + private final Feature.Support support; + + private PubSubFeature(Feature.Support support) { + this.feature = name().replace('_', '-'); + this.qualifiedFeature = PubSub.NAMESPACE + '#' + this.feature; + this.support = support; + } + + public String getFeatureName() { + return feature; + } + + @Override + public String toString() { + return qualifiedFeature; + } + + public Feature.Support support() { + return support; + } + + @Override + public int length() { + return qualifiedFeature.length(); + } + + @Override + public char charAt(int index) { + return qualifiedFeature.charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) { + return qualifiedFeature.subSequence(start, end); + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubManager.java index 6aca72e53..f2d8124ad 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubManager.java @@ -44,6 +44,7 @@ import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace; import org.jivesoftware.smackx.pubsub.util.NodeUtils; import org.jivesoftware.smackx.xdata.Form; import org.jivesoftware.smackx.xdata.FormField; +import org.jxmpp.jid.BareJid; import org.jxmpp.jid.DomainBareJid; import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; @@ -61,12 +62,12 @@ import org.jxmpp.stringprep.XmppStringprepException; public final class PubSubManager extends Manager { private static final Logger LOGGER = Logger.getLogger(PubSubManager.class.getName()); - private static final Map> INSTANCES = new WeakHashMap<>(); + private static final Map> INSTANCES = new WeakHashMap<>(); /** * The JID of the PubSub service this manager manages. */ - private final DomainBareJid pubSubService; + private final BareJid pubSubService; /** * A map of node IDs to Nodes, used to cache those Nodes. This does only cache the type of Node, @@ -112,8 +113,8 @@ public final class PubSubManager extends Manager { * @param pubSubService the PubSub service. * @return a PubSub manager for the connection and service. */ - public static synchronized PubSubManager getInstance(XMPPConnection connection, DomainBareJid pubSubService) { - Map managers = INSTANCES.get(connection); + public static synchronized PubSubManager getInstance(XMPPConnection connection, BareJid pubSubService) { + Map managers = INSTANCES.get(connection); if (managers == null) { managers = new HashMap<>(); INSTANCES.put(connection, managers); @@ -133,7 +134,7 @@ public final class PubSubManager extends Manager { * @param connection The XMPP connection * @param toAddress The pubsub specific to address (required for some servers) */ - PubSubManager(XMPPConnection connection, DomainBareJid toAddress) + PubSubManager(XMPPConnection connection, BareJid toAddress) { super(connection); pubSubService = toAddress; @@ -356,7 +357,7 @@ public final class PubSubManager extends Manager { * * @return the JID of the PubSub service. */ - public DomainBareJid getServiceJid() { + public BareJid getServiceJid() { return pubSubService; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/filter/EventExtensionFilter.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/filter/EventExtensionFilter.java new file mode 100644 index 000000000..77f9bd27d --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/filter/EventExtensionFilter.java @@ -0,0 +1,36 @@ +/** + * + * Copyright 2015 Florian Schmaus. + * + * 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.filter; + +import org.jivesoftware.smack.filter.StanzaExtensionFilter; +import org.jivesoftware.smackx.pubsub.EventElement; + +/** + * Filter for stanzas with the PubSub 'event' extension. + * + * @author Florian Schmaus + * + */ +public final class EventExtensionFilter extends StanzaExtensionFilter { + + public static final EventExtensionFilter INSTANCE = new EventExtensionFilter(); + + private EventExtensionFilter() { + super(EventElement.ELEMENT, EventElement.NAMESPACE); + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/provider/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/filter/package-info.java similarity index 87% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/pep/provider/package-info.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/filter/package-info.java index d301dad85..f8931b5a2 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pep/provider/package-info.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/filter/package-info.java @@ -16,6 +16,6 @@ */ /** - * TODO describe me. + * Filters for Publish-Subscribe (XEP-60). */ -package org.jivesoftware.smackx.pep.provider; +package org.jivesoftware.smackx.pubsub.filter;