BT

BlazeDS and JMS for PHP Developers, Part 2

Posted by Nathan A. Good on Feb 23, 2010 |

The first part in this series covered integrating Java services, PHP, and Adobe Flash Builder user interfaces (UIs) with Java Messaging Service (JMS) through the use of BlazeDS. It demonstrated how, with a few configuration changes, you can use BlazeDS to connect UIs built in Flash Builder to JMS queues through the MessageBroker servlet. Part 1 also covered another method of integrating PHP with Java and JMS: using Representational State Transfer (REST) web services to place messages on a JMS queue.

Part 2 in this series discusses how to integrate PHP and Java with two other methods. The first method—bridging—allows you to use Java objects from PHP, exposing another method of placing messages on JMS queues from PHP through Java. The second method of integration is using Streaming Text Orientated Messaging Protocol (STOMP), another protocol you can use to communicate with the ActiveMQ implementation of JMS. When ActiveMQ receives the message, it places it on the JMS queue, and the Adobe Flex application receives the message.

Integrating With Php Via Bridging

Part 1 of this series demonstrated how you can send messages from Java to Flex and back using BlazeDS and JMS. Other technologies enable PHP–Java integration, as well, to allow you to place messages on JMS queues indirectly. The Java/PHP Bridge is one of these technologies. It allows you to use the same JMS queues that you’ve already configured and have working in ActiveMQ. With the Java/PHP Bridge, you can write a PHP script that calls a method in a Java class. The method places a JMS message on a queue. The Flex UI, using BlazeDS to connect to the JMS queues, then receives the messages on the queues just as it did with the REST web services.

The PHP/Java Bridge distribution comes with a JavaBridge.war file. Unpack this web archive (WAR) file into ActiveMQ’s webapps/JavaBridge directory, and add the application to the conf/jetty.xml file. The JavaBridge web application contains servlets that receive the messages from the PHP scripts, decode them, and run the Java classes.

The Java example

Because communication between PHP scripts and Java classes can be slow, create a Java class that handles the work in one method. Doing so is known as a façade—a pattern in which you hide more complicated functionality behind a simple method that you expose.

Here is the Java example façade class, called MessageHelper: package com.example.bridge;

import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.util.IndentPrinter;

public class MessageHelper {
    
    private Destination destination;
    private String user = ActiveMQConnection.DEFAULT_USER;
    private String password = ActiveMQConnection.DEFAULT_PASSWORD;
    
    public void sendMessage(String url, String subject, String messageText) {
        
        Connection connection = null;            
  
        try {
            boolean isTopic = true;
            boolean isPersistent = false;
            
            System.out.println("Using URL:  <" + url + ">");
            System.out.println("Using Subject:  <" + subject + ">");
            System.out.println("Sending Message Text:  <" + messageText + ">");
            
            ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user, password, url);
            connection = connectionFactory.createConnection();
            connection.start();

            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

            if (isTopic) {
                destination = session.createTopic(subject);
            } else {
                destination = session.createQueue(subject);
            }

            // Create the producer.
            MessageProducer producer = session.createProducer(destination);
            if (isPersistent) {
                producer.setDeliveryMode(DeliveryMode.PERSISTENT);
            } else {
                producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            }

            TextMessage message = session.createTextMessage(messageText);
            
            producer.send(message);

            System.out.println("Done.");

            // Use the ActiveMQConnection interface to dump the connection
            // stats.
            ActiveMQConnection c = (ActiveMQConnection)connection;
            c.getConnectionStats().dump(new IndentPrinter());

        } catch (Exception e) {
            System.out.println("Caught: " + e);
            e.printStackTrace();
        } finally {
            try {
                connection.close();
            } catch (Throwable ignore) {
            }
        }
        
    }

}

The Java class has a single method - sendMessage - that takes the URL of the JMS destination, the name of the topic used, and the message.

Put the completed class into a Java archive (JAR) file, and then place the JAR in the WEB-INF/lib folder of the JavaBridge web application folder (webapps/JavaBridge). You put the JAR into the class path (lib folder) of the JavaBridge web application, because the JavaBridge web application is actually instantiating the Java class. The methods on the MessageHelper are executed in the same virtual machine (VM) as the web server—in this case, the Jetty instance that comes with ActiveMQ.

PHP example

The PHP script here uses the Java.inc files that come with the PHP/Java Bridge. It then creates the Java object and calls the method:

<?php

require_once ("java/Java.inc");

java_autoload('messageHelper.jar');

$helper = java('com.example.bridge.MessageHelper');

$url = 'tcp://localhost:61616';
$subject = '/topic/MyTopic/';
$message = 'Hello, world!!';

$helper->sendMessage($url, $subject, $message);

echo "Message sent";

?>

The java_autoload() method loads the JAR in the PHP script. The java() method loads the Java object using the fully qualified Java object name. After the Java object is loaded, the PHP script calls the sendMessage() method via the configured endpoint for the Java/PHP Bridge.

The endpoint for the Java/PHP Bridge is configured in the Java.inc file in the java folder. Changing the endpoint allows you to execute the PHP script in a different web server. If you already have a web server configured with PHP, you can place this script in a web document folder for that server and execute it. For your PHP script to run correctly, you must also include the java folder that comes with the distribution in the same folder as your script (see the PHP/Java Bridge for details).

In this example, the bridge is only built between PHP and Java, allowing the PHP code to call Java objects. The bridge from Java to PHP is unnecessary for this example.

Example in action: receiving and sending with BlazeDS

To see this example in action, start the Flex application. In a different browser, run the PHP script that connects to the PHP/Java Bridge. You will see the message “Hello, world” in the Flex UI.

Integration With Php Via Stomp

STOMP is another technology that you can use to bridge the gap between PHP and the ActiveMQ JMS implementation. In this example, the ActiveMQ JMS implementation receives the message from the PHP script through STOMP, then ActiveMQ routes the message to the JMS topic that the Flex UI is consuming.

STOMP overview

STOMP is a protocol for sending messages using many different clients. Although ActiveMQ has built-in support for STOMP, you can also use STOMP to communicate with JMS using libraries such as StompConnect.

The example here demonstrates using the built-in support for STOMP in ActiveMQ. The message broker that works with STOMP needs to be turned on first in the conf/activemq.xml file:

<transportConnectors>
    <transportConnector name="openwire" uri="tcp://0.0.0.0:61616" />
    <transportConnector name="stomp" uri="stomp://0.0.0.0:61613" />
</transportConnectors>

After adding the configuration for the STOMP broker, restart ActiveMQ. When ActiveMQ starts, it will print messages to the log file saying that the “stomp” connector has been started:

INFO | Connector openwire Started

INFO | Listening for connections at: stomp://silverstreak.local:61613

Messages sent from your PHP scripts via STOMP are received by ActiveMQ, placed on the JMS topics or queues, and are received by the same consumers. Sending the messages via STOMP still allows the Flex interface to receive the same messages without any changes to the Flex code or configuration. In this manner, using STOMP to send messages to ActiveMQ is quite transparent to the rest of the application.

PHP code

You can use the following PHP script to send an example message using STOMP to the same MyTopic JMS topic used throughout this article. This code uses the Stomp.php class from FuseSource. The Stomp.php class provides a simplified way to send the messages from PHP. To use the class, you must download the distribution and copy the files into the same directory as the example script shown here: <?php

try {
    // include a library
    require_once("Stomp.php");
    // make a connection
    $con = new Stomp("tcp://localhost:61613");
    // connect
    $con->connect();
    // send a message to the queue
    $con->send("/topic/MyTopic", "Hello, world");
    echo "Sent message with body 'test'\n";
    $con->disconnect();

} catch (Exception $e) {
    var_dump($e->getMessage());
}

?>

The code attaches to the ActiveMQ server on port 61613 and sends a small text message (“Hello, world”). Then, it disconnects from the STOMP connector.

ActiveMQ routes the message to the appropriate topic. The Flex application will be able to receive the message, because it is subscribed to the topic.

Example in action

To see this example in action, open the Flex application once again. Open a different browser, and with it, run the PHP script that you created. The “Hello, world” message will appear in the Flex application.

Using JNDI

All of the examples in this series have used the names of the queues and topics (for example, /topic/MyTopic) directly for the purposes of keeping them simple. However, in a production system using JMS, the name of the topics or queues might be configured using Java Naming and Directory Interface (JNDI) instead of hard-coded values.

JNDI is a Java standard that allows you to abstract the actual name of the JMS queue, topic, or even host name. JNDI is a lot like using Domain Name System (DNS) to enable the use of host names instead of IP addresses to identify hosts. Using JNDI allows you to change the locations and implementations of your topics or queues on the server without having to update any of your code.

Aside from abstracting the names of the topics and queues, JNDI provides another useful feature: the ability to write your Java code using Java Platform, Enterprise Edition (Java EE) interfaces for the JMS objects. Using interfaces instead of concrete implementations makes your Java code less dependent on a specific vendor.

Consider the following example Java code:

javax.naming.Context ctx = new javax.naming.InitialContext();
javax.jms.ConnectionFactory factory = (javax.jms.ConnectionFactory)ctx.lookup("ConnectionFactory");
javax.jms.Connection conn = factory.createConnection();
javax.jms.Destination destination = (javax.jms.Destination)jndiContext.lookup("MyTopic");
javax.jms.Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
// send the message...
javax.jms.MessageProducer producer = session.createProducer(destination);
javax.jms.TextMessage message = session.createTextMessage();
message.setText("Hello, world!");
producer.send(message);
conn.close();

Instead of using the ActiveMQConnectionFactory concrete implementation, this Java code uses the InitialContext object to “look up” the specific connection factory implementation. Then, the code gets the reference to the JMS topic using the same lookup method on the InitialContext object. The result is that this example code contains no references to ActiveMQ directly.

A disadvantage to using JNDI—aside from learning how to use it in Java code—is the need to provide some additional configuration to obtain an initial JDNI context. ActiveMQ provides a simple JNDI InitialContextFactory for this. (See the ActiveMQ support page for more information). The disadvantage of additional configuration can be outweighed by the advantage of being able to deploy and execute the Java code without modifications to application servers by different vendors. If switching vendors is a possibility in your environment, you may consider using JNDI to help abstract the details.

Network Considerations

The integration solutions provide the ability for PHP and Flex clients to communicate with the Java/JMS technologies over a network. Because you can deploy the different parts to different web servers, some consideration must be given to network access when evaluating the integration technologies.

If firewalls exist between the PHP, Flex, and Java/JMS services, the ports that are allowed may affect your decision of which method of integration to use. Because BlazeDS connects Flex UIs to JMS via a MessageBroker servlet, only the standard port 80 needs to be accessible on the server (or whichever port the web application server is bound) from the Flex UI.

ActiveMQ uses nonstandard ports when listening for messaging, but if ActiveMQ is running on the same physical machine as the web application server executing BlazeDS, the port (61616 for the “openwire” connector) may be restricted to the localhost interface and not exposed publicly.

Your web application server can expose REST web services on port 80, making them a relatively easy method of integration across networks and servers. For this reason, many people choose web services.

The PHP/Java Bridge uses a servlet deployed in the JavaBridge web application on the web application server to expose the Java classes to PHP via its Extensible Markup Language (XML) streaming mechanism. Because the bridge is installed as a servlet, it too is available from the web server’s standard port.

However, using STOMP requires that a nonstandard port be open between the PHP script and the STOMP message broker (ActiveMQ). The port in these examples is 61613. If network access to this port is restricted, STOMP may not be a good solution for integrating PHP scripts with the Flex UI and Java/JMS services.

Summary

JMS is a messaging service that supports topics and queues, and it has many features that make it a good choice for robust messaging. BlazeDS allows your Flex applications to send messages from Flex clients to JMS implementations without much effort.

Part 1 of this series introduced JMS messaging and demonstrated how to configure BlazeDS to communicate with JMS queues. It also introduced a way to integrate your PHP applications with JMS using REST services implemented in Java, allowing your Flex UIs to receive messages from your PHP scripts.

This article covered using two additional methods of sending messages to JMS topics or queues from PHP. The PHP/Java Bridge is an open source project that provides a framework for calling Java classes from PHP scripts. By writing a single Java class—called a façade—you can offer your PHP scripts the ability to send messages to JMS to be received by your Flex UI. STOMP is a protocol with supporting libraries implemented in several languages. Using STOMP, you can communicate with a JMS message broker and receive the messages in your Flex application.

Together, these different technologies provide different options for integrating applications that are implemented in PHP, Flex, or Java. Integrating existing applications instead of rewriting them saves you time and effort, and the ability to integrate provides the freedom for you to choose the best implementation that fits your needs.

About the Author

Nathan A. Good lives in the Twin Cities area of Minnesota. Professionally, he does software development, software architecture, and systems administration. When he's not writing software, he enjoys building PCs and servers, reading about and working with new technologies, and trying to get his friends to make the move to open source software. He's written and co-written many books and articles, including Professional Red Hat Enterprise Linux 3, Regular Expression Recipes: A Problem-Solution Approach and Foundations of PEAR: Rapid PHP Development.

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread
Community comments

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Discuss

Educational Content

General Feedback
Bugs
Advertising
Editorial
InfoQ.com and all content copyright © 2006-2014 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT