PubSub Component
Prev | Chapter 8. Configuring the Tigase Server to Load a Component | Next

## PubSub Component

### Configuration

Tigase’s Publish Subscribe component is an XEP-0060 compliant plugin handling all publish and subscribe activity within Tigase server. To enable the component the following should be in your init.properties file

    --comp-name-2 = pubsub
    --comp-class-2 = tigase.pubsub.PubSubComponent

### Pubsub naming

Within Tigase, all pubsub component address MUST be domain-based address and not a JID style address. This was made to simplify communications structure. Tigase will automatically set component names to pubsub.domain, however any messages send to pubsub@domain will result in a SERVICE_UNAVAILABLE error.

Pubsub nodes within Tigase can be found as a combination of JID and node where nodes will be identified akin to service discovery. For example, to address a friendly node, use the following structure:

    <iq to='pubsub.domain'>
      <query node='friendly node'/>
    </iq>

### Configure Roster Maxmimum size

Starting with Tigase v7.1.0, administrators can configure the maximum allowable roster size per user via the init.properties file.

    sess-man/plugins-conf/jabber\:iqa\:roster/max_roster_size=100

This sets the roster limit to 100 entries per user. It can be set to any integer, however by default no limit is set.

### AdHoc Commands

Similar to the HTTP API, AdHoc commands based on groovy scripts can be sent to this component to do a number of tasks. All scripts for these Ad-hoc commands are found at sec/main/groovy/tigase/admin in source distrubitions, or at this link. To use them, the scripts need to be copied into the scripts/admin/pubsub folder in the Tigase installation directory. For all examples, the component address will be pubsub.example.com.

#### Create a Node

Ad-hoc command node: create-node Required role: Service Administrator

Command requires fields node and pubsub#node_type to be filled with proper values for execution. - node Field containing id of node to create. - pubsub#node_type Contains one of two possible values. * leaf-node Node that will be published. * collection Node that will contain other nodes.

Other fields are optional fields that can be set to change configuration of newly create node to different configuration than default.

Example call using TCLMT:

    bin/tclmt.sh -u admin@example.com -p admin123 remote pubsub.example.com create-node example admin@example.com leaf

#### Delete a Node

Ad-hoc command node: delete-node Required role: Service Administrator

Command requires node field to be filled. - node Field containing id of node to delete.

Example call using TCLMT:

    bin/tclmt.sh -u admin@example.com -p admin123 remote pubsub.example.com delete-node example

#### Subscribe to a Node

Ad-hoc command node: subscribe-node Required role: Service Administrator

Command requires node and jids nodes to be filled. - node Field containing node to subscribe to. - jids Field containing list of JIDs to subscribe to the node.

Example call using TCLMT:

    bin/tclmt.sh -u admin@example.com -p admin123 remote pubsub.example.com subscribe-node example admin@example.com,test1@example.com

#### Unsubscribe to a Node

Ad-hoc command node: unsubscribe-node Required role: Service Administrator

Command requires node and jids nodes to be filled. - node Field containing node to unsubscribe to. - jids Field containing list of JIDs to unsubscribe to the node.

Example call using TCLMT:

    bin/tclmt.sh -u admin@example.com -p admin123 remote pubsub.example.com unsubscribe-node example admin@example.com,test2@example.com

#### Publish an item to a Node

Ad-hoc command node: publish-item Required role: Service Administrator

Command requires fields node and entry to be filled. - node Field containing id of node to publish to. - item-id Field may contain id of entry to publish, can be empty. - entry Field should contain multi-line entry content that should be valid XML values for items.

This command due to it’s complexity cannot be easily executed by TCLMT using default remote script which provides support for basic adhoc commands. Example call using TCLMT:

    bin/tclmt.sh -u admin@example.com -p admin123 remote pubsub.example.com publish-item example item-1 '<entry><title>Example 1</title></entry>'

Example Groovy script to execute create-node command using JAXMPP2

    import tigase.jaxmpp.j2se.Jaxmpp
    import tigase.jaxmpp.core.client.AsyncCallback
    import tigase.jaxmpp.core.client.exceptions.JaxmppException
    import tigase.jaxmpp.core.client.xmpp.stanzas.Stanza
    import tigase.jaxmpp.core.client.SessionObject
    import tigase.jaxmpp.j2se.ConnectionConfiguration
    import tigase.jaxmpp.core.client.xml.Element
    import tigase.jaxmpp.core.client.xml.DefaultElement
    import tigase.jaxmpp.core.client.xmpp.forms.JabberDataElement

    Jaxmpp jaxmpp = new Jaxmpp();

    jaxmpp.with {
        getConnectionConfiguration().setConnectionType(ConnectionConfiguration.ConnectionType.socket)
        getConnectionConfiguration().setUserJID("admin@example.com")
        getConnectionConfiguration().setUserPassword("admin123")
    }

    jaxmpp.login(true);

    def packet = IQ.create();
    packet.setAttribute("to", "pubsub.example.com");

    Element command = new DefaultElement("command");
    command.setXMLNS("http://jabber.org/protocol/commands");
    command.setAttribute("node", "create-node");
    packet.addChild(command);

    Element x = new DefaultElement("x");
    x.setXMLNS("jabber:x:data");

    command.addChild(x);

    def data = new JabberDataElement(x);
    data.addTextSingleField("node", "example");
    data.addListSingleField("pubsub#node_type", "leaf");

    jaxmpp.send(packet, new AsyncCallback() {
        void onError(Stanza responseStanza, tigase.jaxmpp.core.client.XMPPException.ErrorCondition error) throws JaxmppException {
            println "received error during processing request";
        }

        void onSuccess(Stanza responseStanza) throws JaxmppException {
            x = responseStanza.getFirstChild("command").getFirstChid("x");
            data = new JabberDataElement(x);
            def error = data.getField("Error");
            println "command executed with result = " + (error ? "failure, error = " + error.getFieldValue() : "success");
        }

        void onTimeout() {
            println "command timed out"
        }
    });

    Thread.sleep(30000);
    jaxmpp.disconnect();

### PubSub Node Presence Protocol

Occupant Use Case === Log in to Pubsub Node To log in to PubSub Node user must send presence to PubSub component with additional information about node:

    <presence
        from='hag66@shakespeare.lit/pda'
        id='n13mt3l'
        to='pubsub.shakespeare.lit'>
      <pubsub xmlns='tigase:pubsub:1' node='princely_musings'/>
    </presence>

Component will publish this information in node:

    <message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo'>
      <event xmlns='http://jabber.org/protocol/pubsub#event'>
        <items node='princely_musings'>
          <item>
            <presence xmlns='tigase:pubsub:1' node='princely_musings' jid='hag66@shakespeare.lit/pda' type='available'/>
          </item>
        </items>
      </event>
    </message>
    <message from='pubsub.shakespeare.lit' to='bernardo@denmark.lit' id='bar'>
      <event xmlns='http://jabber.org/protocol/pubsub#event'>
        <items node='princely_musings'>
          <item>
            <presence xmlns='tigase:pubsub:1' node='princely_musings' jid='hag66@shakespeare.lit/pda' type='available'/>
          </item>
        </items>
      </event>
    </message>

And then will send notification with presences of all occupants to new occupant.

#### Log out from PubSub Node

To logout from single node, user must send presence stanza with type unavailable:

    <presence
        from='hag66@shakespeare.lit/pda'
        type='unavailable'
        to='pubsub.shakespeare.lit'>
      <pubsub xmlns='tigase:pubsub:1' node='princely_musings'/>
    </presence>

Component will send events to all occupants as described:

    <message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo'>
      <event xmlns='http://jabber.org/protocol/pubsub#event'>
        <items node='princely_musings'>
          <item>
            <presence xmlns='tigase:pubsub:1' node='princely_musings' jid='hag66@shakespeare.lit/pda' type='unavailable'/>
          </item>
        </items>
      </event>
    </message>

If component receives presence stanza with type unavailable without specified node, then component will log out user from all nodes he logged before and publish events.

#### Retrieving list of all Node Subscribers

To retrieve list of node subscribers, node configuration option tigase#allow_view_subscribers must be set to true:

    <iq type='set'
        from='hamlet@denmark.lit/elsinore'
        to='pubsub.shakespeare.lit'
        id='config2'>
      <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
        <configure node='princely_musings'>
          <x xmlns='jabber:x:data' type='submit'>
            <field var='FORM_TYPE' type='hidden'>
              <value>http://jabber.org/protocol/pubsub#node_config</value>
            </field>
            <field var='tigase#allow_view_subscribers'><value>1</value></field>
          </x>
        </configure>
      </pubsub>
    </iq>

When option is enabled, each subscriber may get list of subscribers the same way as owner.

    <iq type='get'
        from='hamlet@denmark.lit/elsinore'
        to='pubsub.shakespeare.lit'
        id='subman1'>
      <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
        <subscriptions node='princely_musings'/>
      </pubsub>
    </iq>

There is extension to filter returned list:

    <iq type='get'
        from='hamlet@denmark.lit/elsinore'
        to='pubsub.shakespeare.lit'
        id='subman1'>
      <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
        <subscriptions node='princely_musings'>
            <filter xmlns='tigase:pubsub:1'>
                <jid contains='@denmark.lit' />
            </filter>
        </subscriptions>
      </pubsub>
    </iq>

In this example will be returned all subscriptions of users from domain "denmark.lit".

### Store Full XML of Last Presence

A new feature has been implemented in v7.1.0 that allows Tigase to store a more detailed <unavailable/> presence stanza to include timestamps and other information.

#### Requirements

Ensure that presence-offline plugin is enabled in init.properties. To do this, add +presence-offline to the --sm-plugins line.

The following two lines configure options to broadcast probes to offline users.

    sess-man/plugins-conf/skip-offline=false
    sess-man/plugins-conf/skip-offline-sys=false

Without these lines, Tigase will not send presence probes to users that the server knows to be offline.

The full XML presence is stored under the tig_pairs table with a pkey of last-unavailable-presence will look like this:

    <presence from="user@example.com" xmlns="jabber:client" type="unavailable">
    <status>Logged out</status>
    <delay stamp="2015-12-29T16:51:50.748Z" xmlns="urn:xmpp:delay"/></presence>

As you can see, the plugin has added a delay stamp which indicates the last time they were seen online. This may be suppressed by using the following line in your init.properties file.

    sess-man/plugins-conf/delay-stamp=false

You may also limit probe responses only to newly connected resources.

    sess-man/plugins-conf/probe-full-jid=true

When a user logs on, they will receive the same full unavailable presence statements from contacts not logged in. Also the repository entry containing their last unavailable presence will be removed.

NOTE: This will increase traffic with users with many people on their rosters.

### Offline Message Sink

#### Description

Messages sent to offline users is published in PubSub node, from where that message is sent to all the node subscribers as a PubSub notification.

    <message from='pubsub.coffeebean.local' to='bard@shakespeare.lit' id='foo'>
      <event xmlns='http://jabber.org/protocol/pubsub#event'>
        <items node='message_sink'>
          <item id='ae890ac52d0df67ed7cfdf51b644e901'>
            <message type="chat" xmlns="jabber:client" id="x2ps6u0004"
              to="userB_h6x1bt0002@coffeebean.local"
              from="userA_uyhx8p0001@coffeebean.local/1149352695-tigase-20">
              <body>Hello</body>
            </message>
          </item>
        </items>
      </event>
    </message>

#### Configuration

The PubSub node must be created and configured beforehand:

##### Create node

    <iq type='set'
        to='pubsub.coffeebean.local'
        id='create1'>
      <pubsub xmlns='http://jabber.org/protocol/pubsub'>
        <create node='message_sink'/>
      </pubsub>
    </iq>

After that is done, you need to add SessionManager as a publisher:

##### Add sess-man as publisher

    <iq type='set'
        to='pubsub.coffeebean.local'
        id='ent2'>
      <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
        <affiliations node='message_sink'>
          <affiliation jid='sess-man@coffeebean.local' affiliation='publisher'/>
        </affiliations>
      </pubsub>
    </iq>

Finally, the AMP plugin must be configured as well

##### init.properties configuration

    sess-man/plugins-conf/amp/msg-pubsub-jid=pubsub.coffeebean.local
    sess-man/plugins-conf/amp/msg-pubsub-node=message_sink
    sess-man/plugins-conf/amp/msg-pubsub-publisher=sess-man@coffeebean.local

Of course be sure that AMP plugin is in your --sm-plugins line.

#### Usage

Because these sinks use a standard PubSub component, administration of the sink node is identical to any other PubSub node. XEP-0060 defines standard PubSub usage and management.

##### Managing Subscriptions

###### Add new Subscriber

    <iq type='set'
        to='pubsub.coffeebean.local'
        id='subman2'>
      <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
        <subscriptions node='message_sink'>
          <subscription jid='bard@shakespeare.lit' subscription='subscribed'/>
        </subscriptions>
      </pubsub>
    </iq>

###### Remove Subscriber

    <iq type='set'
        to='pubsub.coffeebean.local'
        id='subman2'>
      <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
        <subscriptions node='message_sink'>
          <subscription jid='bard@shakespeare.lit' subscription='none'/>
        </subscriptions>
      </pubsub>
    </iq>

### PubSub Schema Changes

Tigase PubSub Component is currently version 3.2.0 which is introduced in Tigase server v7.1.0

#### PubSub 3.2.0 Changes

PubSub v 3.2.0 adds a new procedure TigPubSubGetNodeMeta which supports PubSub metadata retrieval while conducting a disco#info query on nodes.

You will need to upgrade your database if you are not using v3.2.0 schema. Tigase will report being unable to load PubSub component if you do not have this schema version.

The MySQL schema can be found Here.

The Derby schema can be found Here.

The PostGRESQL schema can be found Here.

The MS SQL schema can be found Here.

The same files are also included in all distributions of v7.1.0 in [tigaseroot]/database/ . All changes to database schema are meant to be backward compatible.

For instructions how to manually upgrade the databases, please refer to Tigase v7.1.0 Schema Updates section.

#### PubSub 3.1.0 Changes

The PubSub Schema has been streamlined for better resource use, this change affects all users of Tigase. To prepare your database for the new schema, first be sure to create a backup! Then apply the appropriate pubsub schema to your MySQL and it will add the new storage procedure.

The MySQL schema can be found Here.

The Derby schema can be found Here.

The PostGRESQL schema can be found Here.

The MS SQL schema can be found Here.

The same files are also included in all distributions of v7.1.0 in [tigaseroot]/database/ . All changes to database schema are meant to be backward compatible.

#### PubSub v3.0.0 Changes

To update older installations of Tigase to the PubSub Schema v3.0.0 follow these instructions. Note this should be done before upgrading to PubSub v3.1.0.

Step by Step guide.

##### Prepare Old Database for Upgrade

In database directory of Tigase installation you will find SQL files which will prepare old database schema for upgrade using following this naming pattern: <database_type>-pubsub-schema-3.0.0-pre-upgrade.sql Where <database_type> can be one of the following: mysql, sqlserver, ie. for MySQL you will find the file mysql-pubsub-schema-3.0.0-pre-upgrade.sql. You need to execute statements from this file on your source database, which will drop old procedures and functions used to access database and also this statements will rename old tables by adding suffix _1 to each of old tables. Example:

MySQL
  mysql -u tigase -p tigase_pubsub < database/mysql-pubsub-schema-3.0.0-pre-upgrade.sql
MS SQL
  sqlcmd -S %servername% -U %root_user% -P %root_pass% -d %database% -i database\sqlserver-pubsub-schema-3.0.0-pre-upgrade.sql

##### Update Tigase PubSub Component

For this you need to copy the Tigase PubSub Component jar file to jars directory inside Tigase XMPP Server installation directory. It is also recommended to copy files from database directory of Tigase PubSub Component to database directory in Tigase XMPP Server installation directory.

If you happen to use one of the the distribution packaged (either installer or -dist-max flavored archive) then all required files are already available - both new schema files will be available in database/ directory as well as both versions of PubSub component will be present in jars/ directory - PubSub3 as tigase-pubsub.jar and PubSub2 as tigase-pubsub-2.2.0.jar.old (provided for compatibility reasons).

##### Load New Schema

In the database directory you will find files containing new schemas for:

- MySQL - mysql-pubsub-schema-3.0.0.sql
- PostgreSQL - postgresql-pubsub-schema-3.0.0.sql
- MSSQL - sqlserver-pubsub-schema-3.0.0.sql
- DerbyDB - derby-pubsub-schema-3.0.0.sql and pubsub-db-create-derby.sh

For most databases, with the exception of Derby, you only need to execute statements from the proper file. For example:

MySQL
  mysql -u tigase -p tigase_pubsub < database/mysql-pubsub-schema-3.0.0.sql
MS SQL
  sqlcmd -S %servername% -U %root_user% -P %root_pass% -d %database% -i database\sqlserver-pubsub-schema-3.0.0.sql
PostgreSQL
  psql -h $DB_HOST -q -U ${USR_NAME} -d $DB_NAME -f database/sqlserver-pubsub-schema-3.0.0.sql

For DerbyDB you need to execute the pubsub-db-create-derby.sh script and pass proper JDBC URI to database to which you want to load schema (if database does not exist, it will be created).

    database/pubsub-db-create-derby.sh

NOTE: It is possible to use same database which was used before - then after upgrade you will have new tables and old tables with _1 suffix.

##### Execute Migration Utility

In the /database directory you will find the pubsub-db-migrate.sh file which you need to execute and pass arguments with JDBC URIs needed to connect to source and destination database. If you used dedicated tables for PubSub you will also need to pass a class name used to access database (value of pubsub/pubsub-repo-class variable from etc/init.properties file).

Example for dedicated table used for PubSub:

    database/pubsub-db-migrate.sh -in-repo-class tigase.pubsub.repository.PubSubDAO
    -in 'jdbc:mysql://localhost/tigase_pubsub?user=tigase&password=passwd'
    -out 'jdbc:mysql://localhost/tigase_pubsub?user=tigase&password=passwd'

Example for use without dedicated PubSub tables:

    database/pubsub-db-migrate.sh
    -in 'jdbc:mysql://localhost/tigase?user=tigase&password=passwd'
    -out 'jdbc:mysql://localhost/tigase?user=tigase&password=passwd'

Example for use with dedicated tables in a Windows environment:

    database/pubsub-db-migrate.cmd -in-repo-class tigase.pubsub.repository.PubSubDAO
    -in 'jdbc:sqlserver://<hostname>\\<instance>:<port>;databaseName=<name>;user=tigase;password=tigase;schema=dbo;lastUpdateCount=false'
    -out 'jdbc:sqlserver://<hostname>\\<instance>:<port>;databaseName=<name>;user=tigase;password=tigase;schema=dbo;lastUpdateCount=false'

During execution this utility will report information about migration of PubSub data to the new schema, and the same information will be store in pubsub_db_migration.log.

##### Finish

After successful migration you will have all data copied to new tables. Old tables will be renamed by adding suffix _1. After verification that everything works OK, you can delete old tables and it’s content as it want be used any more.

Prev | Up | Next
Advanced Message Processing - AMP XEP-0079 | Home | Server Monitoring