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.