**UPDATE x2: **
Yes Supported… See code snippet at bottom.
You must use the correct subscription configuration to correctly set the node depth, otherwise nothing…
Thanks for the reply,
I did some additional testing yesterday but was still not able to get subscriptions to a CollectionNode to respond when a LeafNode update occurs. I’m not sure if there are “ordering” issues around the creation and subscription process, but would really like to get CollectionNodes and PubSub working (at least as far as XEP-060)
Here’s a basic outline of how I approached with code samples of key points:
1) Create a “manager” account in main() which opens a connection to Openfire and creates a CollectionNode named “TestCollection”.
/*
* Creates the collection node for everyone in the system, adds our own listeners to the node and
* subscribes the main function to updadtes from that node.
*/
public static boolean createCollectionNode(){
PubSubManager m_manager = new PubSubManager(m_xmppConnection, SimpleConstants.SERVER_SERVICE);
CollectionNode node = null;
String subscriber = SimpleConstants.MANAGER_NAME + "@" + m_xmppConnection.getServiceName(); ConfigureForm nodeConfig = new ConfigureForm(FormType.submit);
nodeConfig.setPersistentItems(false);
nodeConfig.setDeliverPayloads(true);
nodeConfig.setAccessModel(AccessModel.open);
nodeConfig.setPublishModel(PublishModel.open);
nodeConfig.setNodeType(NodeType.collection); try {
node = (CollectionNode) m_manager.getNode(SimpleConstants.COLLECTION_NODE_NAME); } catch (XMPPException e) {} try {
if (null == node){
node = (CollectionNode) m_manager.createNode(SimpleConstants.COLLECTION_NODE_NAME, nodeConfig);
}
else {
node.sendConfigurationForm(nodeConfig);
} // Remove any existing subscriptions...
List<Subscription> subscriptions = node.getSubscriptions();
for (Subscription s : subscriptions){
if (s.getJid().equalsIgnoreCase(subscriber)){
node.unsubscribe(subscriber);
}
} node.addConfigurationListener(new MyNodeConfigListener());
node.addItemEventListener(new MyEventListener());
SubscribeForm subscriptionForm = new SubscribeForm(FormType.submit);
subscriptionForm.setDeliverOn(true);
subscriptionForm.setDigestFrequency(5000);
subscriptionForm.setDigestOn(true);
subscriptionForm.setIncludeBody(true);
node.subscribe(subscriber, subscriptionForm); } catch (XMPPException e) {
System.out.println("This is bad!! Could not create client collection node: " + e.getLocalizedMessage());
} return true;
}
2) Using the same connection in main(), I create test accounts for 5 publishers. These will be scheduled through an executor pool to post random time updates.
/*
* CREATE THE PUBLISHED NODE
* */
public boolean createNode(){
ConfigureForm nodeConfigForm = new ConfigureForm(FormType.submit);
nodeConfigForm.setPersistentItems(false);
nodeConfigForm.setDeliverPayloads(true);
nodeConfigForm.setAccessModel(AccessModel.open);
nodeConfigForm.setPublishModel(PublishModel.open);
nodeConfigForm.setCollection(SimpleConstants.COLLECTION_NODE_NAME); m_manager = new PubSubManager(m_xmppConnection, SimpleConstants.SERVER_SERVICE); try {
m_node = (LeafNode) m_manager.getNode(m_nodeId);
} catch (XMPPException e) {} try {
if (null == m_node){
m_node = (LeafNode) m_manager.createNode(m_nodeId, nodeConfigForm);
}
else {
m_node.sendConfigurationForm(nodeConfigForm);
}
} catch (XMPPException e){
System.out.println("Exception occured while trying to create node: " + e.getLocalizedMessage());
e.printStackTrace(); } if (m_listenSelf)
m_node.addItemEventListener(m_pubsubListener); return true;
} /*
* PUBLISH TIME....
*/
public void publishTime(){
System.out.print('.');
SimplePayload payload = new SimplePayload("time", SimpleConstants.SERVER_SERVICE,
"<time xmlns='pubsub:testnode1:time'>" +
"<title>" + String.valueOf(System.currentTimeMillis()) + "</title>" +
"</time>"); PayloadItem payloadItem = new PayloadItem("time", m_nodeId, payload);
m_node.publish(payloadItem); }
3) After the creation of the test accounts, I do a little sanity checking. I’m observing that each of the different XMPPConnection objects and/or PubSubManagers reports a different set of subscribed accounts. With the snippet below, only the subscriptions created through “manager” are listed, even though a separate “receiver” is created and subscribed elsewhere. I check the subscription status within the Postgresql database, and the CollectionNode shows both of the two subscribers I have configured, the “manager” and the “receiver” are properly listed.
// SANITY CHECK!!!!!
System.out.println("Completed initialization o clients, begin sanity check...");
PubSubManager manager = new PubSubManager(m_xmppConnection, SimpleConstants.SERVER_SERVICE);
try {
DiscoverItems items = manager.discoverNodes(SimpleConstants.COLLECTION_NODE_NAME);
Iterator<org.jivesoftware.smackx.packet.DiscoverItems.Item> itemItor = items.getItems();
while (itemItor.hasNext()){
org.jivesoftware.smackx.packet.DiscoverItems.Item i = itemItor.next();
System.out.println("Child of node: "+ SimpleConstants.COLLECTION_NODE_NAME + " found :" + i.getNode());
}
} catch (XMPPException e) {} // MORE SANITY CHECK! CANT HAVE TOO MUCH SANITY CHECKING...
System.out.println("More sanity checking...");
try {
List<Subscription> subscriptions = manager.getSubscriptions(); Iterator<Subscription> subItor = subscriptions.iterator();
while (subItor.hasNext()){
Subscription s = subItor.next();
System.out.println("Subscription to node: " + s.getNode() + " by " + s.getJid());
}
} catch (XMPPException e1) {}
Here’s what the resulting subscription check looks like for the “receiver” node:
<iq id="xDwvy-89" to="testreceiver@locator.adspore.com/Smack" from="pubsub.locator.adspore.com" type="result">
<pubsub xmlns="http://jabber.org/protocol/pubsub">
<subscriptions>
<subscription jid="testreceiver@locator.adspore.com" node="TestCollection" subid="7X5JhTW1S3NpY3X0lJteEfxXDnIsoC17TV85i15u" subscription="subscribed"/>
</subscriptions>
</pubsub>
</iq>
And here’s what the subscription check looks like for the “manager” node:
<iq id="xDwvy-11" to="test_account_mgr@locator.adspore.com/Smack" from="pubsub.locator.adspore.com" type="result">
<pubsub xmlns="http://jabber.org/protocol/pubsub">
<subscriptions node="TestCollection">
<subscription jid="test_account_mgr@locator.adspore.com" subid="j7pU9031Hh88MLCG2NCR4QiK7CQRMAJR89HXnKrj" subscription="subscribed"/>
</subscriptions>
</pubsub>
</iq>
Here’s what the output of the code above looks like when it’s run:
SimpleListener.cleanupAccount()... Has subscription:testreceiver@locator.adspore.com to Node:TestCollection
SimpleListener... Checking subscriptions on local PubSubManager...
Subscription to node: TestCollection by testreceiver@locator.adspore.com
Completed initialization o clients, begin sanity check...
Child of node: TestCollection found :testClient4
Child of node: TestCollection found :testClient3
Child of node: TestCollection found :testClient1
Child of node: TestCollection found :testClient2
Child of node: TestCollection found :testClient0
More sanity checking...
Subscription to node: TestCollection by test_account_mgr@locator.adspore.com
Completed scheduling
**4) **Begin the scheduling and observe the results… The “publish” method is shown in step #2 above, simply putting up the current time.
// Schedule all of the clients...
itor = clients.iterator();
Random random = new Random();
while (itor.hasNext()){
SimpleBroadcaster client = itor.next();
long initial = 2L;
long interval = 1L + ((long)(random.nextInt(4)));
m_executor.scheduleAtFixedRate(new ClientExecutor(client), initial, interval, TimeUnit.SECONDS);
}
System.out.println("Completed scheduling"); // Wait to quit....
try {
Thread.sleep(1000 * 60 * 2);
} catch (InterruptedException e) {} }
} static class ClientExecutor implements Runnable {
SimpleBroadcaster m_broadcaster; public ClientExecutor(SimpleBroadcaster broadcaster){
m_broadcaster = broadcaster;
} public void run(){
m_broadcaster.publishTime();
}
}
ANSWER:
Must use the correct form configuration to set the depth and notification type. Disregard the “all” subscription type, I modified my Openfire instance to properly handle both node additions/deletions as well as publishing events.
// Get the node
Node node = mgr.getNode("gamedata/locations");
SubscribeForm form = new SubscribeForm(new ConfigureForm(FormType.submit));
FormField field = new FormField("FORM_TYPE");
field.setType(FormField.TYPE_HIDDEN);
field.addValue("http://jabber.org/protocol/pubsub#subscribe_options");
form.addField(field);
field = new FormField("pubsub#subscription_type");
field.setType(FormField.TYPE_TEXT_SINGLE);
field.addValue("all");
form.addField(field);
field = new FormField("pubsub#subscription_depth");
field.setType(FormField.TYPE_TEXT_SINGLE);
field.addValue("all");
form.addField(field);
node.addItemEventListener(new GeoEventListener<Item>());
node.subscribe(connection.getUser(), form);
Thanks again,
DD