Use Grails Services from PHP with PHP/Java Bridge

While in the process of migrating back-end business logic to Java I was investigating my options for exposing Grails services to PHP. Of course, I could just expose the services as web services and consume them with PHP, but where's the fun in that?

I was interested in PHP's Java connectivity, specifically through the use of the PHP/Java Bridge libraries.

The PHP/Java Bridge is...

"... an implementation of a streaming, XML-based network protocol, which can be used to connect a native script engine, for example PHP, Scheme or Python, with a Java virtual machine. It is up to 50 times faster than local RPC via SOAP, requires less resources on the web-server side. It is faster and more reliable than direct communication via the Java Native Interface, and it requires no additional components to invoke Java procedures from PHP or PHP procedures from Java."

So here's how I got it to work.

First, download the JavaBridge.war to get the required libraries and example web.xml.

Unzip the JavaBridge.war and copy the libs ( JavaBridge.jar, php-script.jar and php-servlet.jar) to your Grails project libs folder $GRAILS_PROJECT_HOME/lib.

Now install the Grails templates so the application's web.xml can be modified.

$> grails install-templates

This will create the file at $GRAILS_PROJECT_HOME/src/templates/war/web.xml.

Edit the newly created web.xml and copy the desired sections from the web.xml located in the JavaBridge.war.

For my proof-of-concept, I only added the following sections (in their respective locations)...

... php.java.servlet.ContextLoaderListener ... PhpJavaServlet php.java.servlet.PhpJavaServlet ... PhpJavaServlet *.phpjavabridge ...

Save the file and start your Grails application.

I'll use the Grails service below as the example moving forward.

package myapp.services 

import myapp.domain.Book 
import org.hibernate.FetchMode 

class MyService { 
  static transactional = false 

  public List getBooks() { 
    return Book.withCriteria { 
      firstResult(1) 
      maxResults(20) 
      fetchMode("author", FetchMode.EAGER) 
    }
  }
}

Next, we set up our PHP test file to access the PHP/Java Proxy.

With your Grails application running browse to the path http://localhost:8080/java/Java.inc and save that file accessible to your PHP application. You can pull this file directly off the server but you'll have to enable the allow_url_includ setting.

// Sets the remote JEE server hosts 
define('JAVA_HOSTS', 'localhost:8080'); 

// Load the PHP helper functions 
require_once('Java.inc');

Now suppose I wanted to access a Grails service from my PHP application. First I have to get ahold of the Grails/Spring application context then I can request the desired beans.

// Sets the remote JEE server hosts 
define('JAVA_HOSTS', 'localhost:8080'); 

// Load the PHP helper functions r
equire_once('Java.inc'); 

// Grab the Grails/Spring ApplicationContext 
$ah = java('org.codehaus.groovy.commons.ApplicationHolder'); 
$ctx = $ah->getApplication()->getMainContext(); 

// Request the service bean 
$myService = $ctx->getBean('myService'); 

// Call method from service 
$books = $myService->getBooks(); 

// Loop through books 
$it = $books->iterator(); 
while(java_values($it->hasNext())==true) { 
  $book = $it->next(); 
  $author = $book->getAuthor(); 
  echo $book->getTitle() . " by " . $author->getPenName(); 
}

As you can see there are some quirks you have to work through but for the most part, it's pretty straight forward. The VM Bridge FAQ can guide you through most of the obstacles of talking to your Java application.