//
// 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.
//

==== JMS

The Apache Karaf MOM (Messaging Oriented Middleware/JMS) is an optional enterprise feature.

You have to install the `jms` feature first:

----
karaf@root()> feature:install jms
----

The `jms` feature doesn't install a JMS broker: it just installs the OSGi service, commands, and MBean to interact with
a JMS broker (not the broker itself).

It means that you have to install a JMS broker itself.

This JMS broker can be available:

* outside of Apache Karaf, as a standalone broker. In that case, Apache Karaf JMS will remotely connect to the JMS broker.
 For instance, you can use this topology with Apache ActiveMQ or IBM WebsphereMQ.
* embedded in Apache Karaf. With this topology, Apache Karaf itself provides a JMS broker service. Apache ActiveMQ provides
 a native support in Apache Karaf.

For instance, you can install Apache ActiveMQ directly in Apache Karaf:

----
karaf@root()> feature:repo-add activemq
Adding feature url mvn:org.apache.activemq/activemq-karaf/LATEST/xml/features
karaf@root()> feature:install activemq-broker
----

The `activemq-broker` feature installs:

* a Apache ActiveMQ broker directly in Apache Karaf, binding to the `61616` port number by default.
* the Apache ActiveMQ WebConsole bound to `http://0.0.0.0:8181/activemqweb` by default.

The Apache Karaf `jms` feature provides an OSGi service to create/delete JMS connection factories in the container
and perform JMS operations (send or consume messages, get information about a JMS broker, list the destinations, ...).

This JMS OSGi service can be manipulated programmatically (see the developer guide for details), using the `jms:*` commands, or using the JMS MBean.

===== Commands

====== `jms:create`

The `jms:create` command creates a JMS connection factory in the Apache Karaf container. It automatically creates a
blueprint XML file in the `deploy` folder containing the JMS connection factory definition corresponding
to the type that you mentioned.

The `jms:create` command accepts different arguments and options:

----
karaf@root()> jms:create --help
DESCRIPTION
        jms:create

        Create a JMS connection factory.

SYNTAX
        jms:create [options] name

ARGUMENTS
        name
                The JMS connection factory name
                (required)

OPTIONS
        -t, --type
                The JMS connection factory type (ActiveMQ, Artemis or WebsphereMQ)
                (defaults to activemq)
        --pool
                The pool mechanism to use for this connection factory
                (defaults to pooledjms)
        --help
                Display this help message
        --url
                URL of the JMS broker. For WebsphereMQ type, the URL is hostname/port/queuemanager/channel
                (defaults to tcp://localhost:61616)
        -p, --password
                Password to connect to the JMS broker
                (defaults to karaf)
        -u, --username
                Username to connect to the JMS broker
                (defaults to karaf)


----

* the `name` argument is required. It's the name of the JMS connection factory. The name is used to identify the connection factory, and to create the connection factory definition file (`deploy/connectionfactory-[name].xml`).
* the `-t` (`--type`) option is required. It's the type of the JMS connection factory. Currently only `activemq` and `webspheremq` types are supported. If you want to use another type of JMS connection factory, you can create the `deploy/connectionfactory-[name].xml` file by hand (using one as template).
* the `--url` option is required. It's the URL used by the JMS connection factory to connect to the broker. If the type is `activemq`, the URL looks like `tcp://localhost:61616`. If the type is `webspheremq`, the URL looks like `host/port/queuemanager/channel`.
* the `-u` (`--username`) option is optional (karaf by default). In the case of the broker requires authentication, it's the username used.
* the `-p` (`--password`) option is optional (karaf by default). In the case of the broker requires authentication, it's the password used.
* the `--pool` option is optional (`pooledjms` by default). It allows you to define the pooling framework you want to use: pooledjms, narayana, transx.


For instance, to create a JMS connection factory for a Apache ActiveMQ broker, you can do:

----
karaf@root()> feature:install pax-jms-activemq
karaf@root()> jms:create -t activemq --url tcp://localhost:61616 test
----

[NOTE]
====
When you use ActiveMQ, Karaf uses `transx` as connection factory pooling framework.
====

[NOTE]
====
The `jms:create` command doesn't install any feature or bundle providing the JMS connection factory classes (and dependencies).
You have to install the required features (for instance `activemq-broker` feature for Apache ActiveMQ), or bundles (for IBM WebsphereMQ) providing the JMS connection factory packages and classes.
====

In the previous example, we assume that you previously installed the `activemq-broker` feature.

We can see the created JMS connection factory:

----
karaf@root()> la
...
151 | Active   |  80 | 0.0.0                 | connectionfactory-test.xml
----

The `connectionfactory-test.xml` file has been created in the `deploy` folder.

By default, the `jms:create` command constructs a JNDI name for the connection factory: `/jms/[name]`.

It means that the connection factory name to use for the other `jms:*` commands is `/jms/[name]`.

====== `jms:delete`

The `jms:delete` command deletes a JMS connection factory. The `name` argument is the name that you used at creation time:

----
karaf@root()> jms:delete test
----

====== `jms:connectionfactories`

The `jms:connectionfactories` command lists the JMS connection factories:

----
karaf@root()> jms:connectionfactories 
JMS Connection Factory
----------------------
/jms/test     
----

====== `jms:info`

The `jms:info` command provides details about the JMS connection factory:

----
karaf@root()> jms:info /jms/test
Property | Value
-------------------
product  | ActiveMQ
version  | 5.9.0
----

You can see the JMS broker product and version.

If the JMS broker requires authentication, you can use the `-u` (`--username`) and `-p` (`--password`) options.

====== `jms:queues`

The `jms:queues` command lists the JMS queues available on a JMS broker. For instance:

----
karaf@root()> jms:queues /jms/test
JMS Queues
----------
MyQueue
----

where `/jms/test` is the name of the JMS connection factory.

If the JMS broker requires authentication, you can use the `-u` (`--username`) and `-p` (`--password`) options.

[NOTE]
====
Depending of the JMS connection factory type, this command may not work.
For now, the command works only with Apache ActiveMQ.
====

====== `jms:topics`

The `jms:topics` command lists the JMS topics available on a JMS broker. For instance:

----
karaf@root()> jms:topics /jms/test
JMS Topics
----------
MyTopic
----

where `/jms/test` is the name of the JMS connection factory.

If the JMS broker requires authentication, you can use the `-u` (`--username`) and `-p` (`--password`) options.

[NOTE]
====
Depending of the JMS connection factory type, this command may not work.
For now, the command works only with Apache ActiveMQ.
====

====== `jms:send`

The `jms:send` command sends a message to a given JMS queue.

For instance, to send a message containing `Hello World` in the `MyQueue` queue, you can do:

----
karaf@root()> jms:send /jms/test MyQueue "Hello World"
----

If the JMS broker requires authentication, you can use the `-u` (`--username`) and `-p` (`--password`) options.

====== `jms:consume`

The `jms:consume` command consumes messages from a JMS queue.

For instance, to consume all messages from `MyQueue`, you can do:

----
karaf@root()> jms:consume /jms/test MyQueue
2 message(s) consumed
----

If you want to consume only some messages, you can define a selector using the `-s` (`--selector`) option.

If the JMS broker requires authentication, you can use the `-u` (`--username`) and `-p` (`--password`) options.

[NOTE]
====
The `jms:consume` command just consumes (so removes) messages from a JMS queue. It doesn't display the messages.
If you want to see the details of messages, you can use the `jms:browse` command.
====

====== `jms:count`

The `jms:count` command counts the number of pending messages into a JMS queue.

For instance, if you want to know the number of messages on `MyQueue`, you can do:

----
karaf@root()> jms:count /jms/test MyQueue
Messages Count
--------------
8
----

If the JMS broker requires authentication, you can use the `-u` (`--username`) and `-p` (`--password`) options.

====== `jms:browse`

The `jms:browse` command browses a JMS queue and display details about messages.

For instance, to browse the `MyQueue` queue:

----
karaf@root()> jms:browse /jms/test MyQueue
Message ID                              | Content        | Charset | Type | Correlation ID | Delivery Mode | Destination     | Expiration | Priority | Redelivered | ReplyTo | Timestamp
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ID:vostro-59602-1387462183019-3:1:1:1:1 | Hello World    | UTF-8   |      |                | Persistent    | queue://MyQueue | Never      | 4        | false       |         | Thu Dec 19 15:10:12 CET 2013
ID:vostro-59602-1387462183019-3:2:1:1:1 | Hello ActiveMQ | UTF-8   |      |                | Persistent    | queue://MyQueue | Never      | 4        | false       |         | Thu Dec 19 15:10:16 CET 2013
ID:vostro-59602-1387462183019-3:3:1:1:1 | Hello Karaf    | UTF-8   |      |                | Persistent    | queue://MyQueue | Never      | 4        | false       |         | Thu Dec 19 15:10:19 CET 2013
----

By default, the messages properties are not displayed. You can use the `-v` (`--verbose`) option to display the properties:

----
karaf@root()> jms:browse -v /jms/test MyQueue
Message ID                              | Content        | Charset | Type | Correlation ID | Delivery Mode | Destination     | Expiration | Priority | Redelivered | ReplyTo | Timestamp                    | Properties
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ID:vostro-59602-1387462183019-3:1:1:1:1 | Hello World    | UTF-8   |      |                | Persistent    | queue://MyQueue | Never      | 4        | false       |         | Thu Dec 19 15:10:12 CET 2013 |
ID:vostro-59602-1387462183019-3:2:1:1:1 | Hello ActiveMQ | UTF-8   |      |                | Persistent    | queue://MyQueue | Never      | 4        | false       |         | Thu Dec 19 15:10:16 CET 2013 |
ID:vostro-59602-1387462183019-3:3:1:1:1 | Hello Karaf    | UTF-8   |      |                | Persistent    | queue://MyQueue | Never      | 4        | false       |         | Thu Dec 19 15:10:19 CET 2013 |
----

If you want to browse only some messages, you can define a selector using the `-s` (`--selector`) option.

If the JMS broker requires an authentication, you can use the `-u` (`--username`) and `-p` (`--password`) options.

====== `jms:move`

The `jms:move` command consumes all messages from a JMS queue and send it to another one.

For instance, to move all messages from `MyQueue` queue to `AnotherQueue` queue, you can do:

----
karaf@root()> jms:move /jms/test MyQueue AnotherQueue
3 message(s) moved
----

===== JMX JMS MBean

The JMX JMS MBean provides the attributes and operations to manipulate the JMS connection factories and JMS messages.

The object name to use is `org.apache.karaf:type=jms,name=*`.

====== Attributes

The `Connectionfactories` attribute provides the list of all JMS connection factories names.

====== Operations

* `create(name, type, url)` creates a JMS connection factory.
* `delete(name)` deletes a JMS connection factory.
* `Map<String, String> info(connectionFactory, username, password)` gets details about a JMS connection factory and broker.
* `int count(connectionFactory, queue, username, password)` counts the number of pending messages on a JMS queue.
* `List<String> queues(connectionFactory, username, password)` lists the JMS queues available on the JMS broker.
* `List<String> topics(connectionFactory, username, password)` lists the JMS topics available on the JMS broker.
* `TabularData browse(connectionFactory, queue, selector, username, password)` browses a JMS queue and provides a table of JMS messages.
* `send(connectionFactory, queue, content, replyTo, username, password)` sends a JMS message to a target queue.
* `int consume(connectionFactory, queue, selector, username, password)` consumes JMS messages from a JMS queue.
* `int move(connectionFactory, source, destination, selector, username, password)` moves messages from a JMS queue to another.
