mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-25 15:52:06 +01:00
Refactor PEP to use PubSub API.
Fixes SMACK-416.
This commit is contained in:
parent
0d6f00873f
commit
33e5c37af8
17 changed files with 479 additions and 453 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<? extends CharSequence> 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<? extends CharSequence> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -209,7 +209,7 @@ public class DiscoverInfo extends IQ implements TypedCloneable<DiscoverInfo> {
|
|||
* @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<DiscoverInfo> {
|
|||
this.variable = feature.variable;
|
||||
}
|
||||
|
||||
public Feature(CharSequence variable) {
|
||||
this(variable.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new feature offered by an XMPP entity or item.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
|||
* <pre>
|
||||
* 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);
|
||||
* </pre>
|
||||
*
|
||||
* @author Jeff Williams
|
||||
* @author Florian Schmaus
|
||||
*/
|
||||
public class PEPManager {
|
||||
public final class PEPManager extends Manager {
|
||||
|
||||
private List<PEPListener> pepListeners = new ArrayList<PEPListener>();
|
||||
private static final Map<XMPPConnection, PEPManager> 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<PEPListener> 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.
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.<p>
|
||||
*
|
||||
* 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:
|
||||
* <pre>
|
||||
* <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>
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public String toXML() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append('<').append(getElementName()).append(" xmlns=\"").append(getNamespace()).append("\">");
|
||||
buf.append(item.toXML());
|
||||
buf.append("</").append(getElementName()).append('>');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -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.<p>
|
||||
*
|
||||
* 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:
|
||||
* <pre>
|
||||
* <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>
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public String toXML() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append('<').append(getElementName()).append(" id=\"").append(id).append("\">");
|
||||
buf.append(getItemDetailsXML());
|
||||
buf.append("</").append(getElementName()).append('>');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -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.<p>
|
||||
*
|
||||
* 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:
|
||||
* <pre>
|
||||
* <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>
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <iq> + <pubsub> and inbound are <message> + <event>.
|
||||
* The provider only deals with inbound, and so it only deals with <message>.
|
||||
*
|
||||
* Anyhoo...
|
||||
*
|
||||
* The way this works is that PEPxxx classes are generic <pubsub> and <message> providers, and anyone who
|
||||
* wants to publish/receive PEPs, such as <tune>, <geoloc>, 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<ExtensionElement> {
|
||||
|
||||
private static final Map<String, ExtensionElementProvider<?>> nodeParsers = new HashMap<String, ExtensionElementProvider<?>>();
|
||||
|
||||
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 <event>.)
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
|
@ -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("<event xmlns='" + PubSubNamespace.EVENT.getXmlns() + "'>");
|
||||
@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("</event>");
|
||||
return builder.toString();
|
||||
}
|
||||
public static EventElement from(Stanza stanza) {
|
||||
return stanza.getExtension(ELEMENT, NAMESPACE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <a href="http://www.xmpp.org/extensions/xep-0060.html#features">XEP-60 § 10</a>
|
||||
*
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<XMPPConnection, Map<DomainBareJid, PubSubManager>> INSTANCES = new WeakHashMap<>();
|
||||
private static final Map<XMPPConnection, Map<BareJid, PubSubManager>> 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<DomainBareJid, PubSubManager> managers = INSTANCES.get(connection);
|
||||
public static synchronized PubSubManager getInstance(XMPPConnection connection, BareJid pubSubService) {
|
||||
Map<BareJid, PubSubManager> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
Loading…
Reference in a new issue