Brücke zwischen den Welten

Integration von PHP mit der Java Enterprise Edition

Markus Eisele

Was PHP für die Weiten des Internets bedeutet, ist vergleichbar mit der Rolle, die Enterprise Java in Unternehmen spielt. Dabei wird PHP ein schneller und kostengünstiger Einsatz nachgesagt, während die Java EE für Stabilität, Performance und unternehmenskritische Anwendungen steht.

Diese Trennung ist in letzter Zeit aber zunehmend unschärfer geworden. JEE ist schneller in der Entwicklung geworden und auch mit PHP kann man mittlerweile guten Gewissens Anwendungen umsetzen, die kritischen funktionalen und nichtfunktionalen Anforderungen genügen. Ein Grund mehr, warum man die Kombination aus beiden immer öfter in Unternehmen antrifft.

Über PHP

Die drei Buchstaben PHP stellen das umgedrehte Akronym für Hypertext Preprocessing dar. Es wurde bereits 1995 entwickelt und in den Anfängen des Internets war es die Lösung zur Erstellung von dynamischen Internetseiten. Auch oder vor allem dank seiner einfachen Erlernbarkeit und der umfangreichen Unterstützung aller relevanten Datenbanken und Internetstandards hat es eine rasende Verbreitung gefunden. Die serverseitigen Quelltexte werden interpretiert und das Ergebnis an den Client übermittelt.
In erster Linie handelt es sich dabei um Texte (xHTML, o.Ä.). Grundsätzlich ist PHP darauf aber natürlich nicht beschränkt. Es können darüber hinaus beliebige Streams (Grafiken, PDF, o.Ä.) generiert werden. Neben diesen klassischen, webbasierten Aufgaben bietet PHP noch eine Programmierschnittstelle für grafische Client Oberflächen. Eine deutliche Verbreitung hat es hier aber nicht gefunden. Wer von PHP spricht, meint also zumeist die Webprogrammiersprache.
Dank vielfacher Erweiterungen und Bibliotheken kann es auch vor allem dort seine Stärken ausspielen. Die Entwicklung von PHP wird von einer Open-Source-Gemeinschaft getragen. Unterstützung erhält diese dabei von Zend und weiteren kommerziellen Herstellern. Eine noch breitere Entwicklergemeinde hat sich um nahezu unzählige Open-Source-Projekte versammelt. Darunter finden sich neben den Klassikern wie beispielsweise Foren-, Shopping- oder Content- Management-Systemen Lösungen für nahezu beliebige Anforderungen.

Klassische Interoperabilität

Neben Java EE und PHP gibt es noch viele weitere Programmiersprachen, die sich für die Umsetzung von webbasierten Anwendungen eignen. Unbestritten stellen die beiden genannten einen bedeutenden Anteil an Installationen und zählen schon allein darum wohl zu den führenden Vertretern auf diesem Gebiet. Gerade zu Zeiten des Web 2.0 fallen bei PHP so schillernde Namen wie flickr, technorati oder auch WordPress und Joomla auf. Kein Wunder also, dass man beide immer wieder im Entwickleralltag antrifft. Und zwar genau mit der bereits

genannten Aufgabenteilung. PHP für den Internetauftritt und JEE für alle Umsetzungen von Anwendungen im Intranet von Unternehmen. Was eine schöne und saubere Aufgabenteilung zwischen den Technologien bedeuten könnte, entspricht auf keinem Fall dem Alltag. Die Prozesse der Unternehmen machen an den Grenzen von Technologien selten Halt. Das bestätigt auch eine Umfrage von der Firma Zend zu dem Thema, ob eine Integration von PHP und Java von Interesse sein könnte. Mit 55% haben mehr als die Hälfte der Befragten dies mit „Ja“ beantwortet.

Die Gründe liegen auf der Hand, und schaut man sich ein einfaches Beispiel an, wird das schnell klar. Ein Unternehmen betreibt eine Internetseite auf Basis des PHP-basierenden Content Management Systems TYPO3. Die Marketingabteilung hat eine komfortable Oberfläche um alle relevanten Inhalte zu editieren und alle Pflegeprozesse sind etabliert. Mit der Einführung einer neuen Produktlinie soll die Darstellung im Internet erweitert werden. Eine manuelle Pflege der Produkte inklusive aller Varianten in mehreren Sprachen bedeutet aber einen kaum zu bewältigenden Mehraufwand. Eine klassische Fragestellung, welche vor allem für mittelständische Unternehmen mit der zunehmenden Bedeutung des Internet an Relevanz gewinnt. In der Vergangenheit wurden für solche Probleme verschiedene, etablierte Lösungswege gewählt. Bekanntester Weg ist die datenseitige Integration. Nächtliche Im- und/oder Exporte glichen Datenbestände zwischen ERP-System und CMS-System ab und versorgten damit den Internetauftritt. Alternativ wurden Datenbanken komplett gespiegelt oder gar Online-Zugriffe auf ERP-Daten erlaubt. Gerade bei den Letztgenannten kämpft man mit allerlei Sicherheitsproblemen.

Aber allen Alternativen gemeinsam bleibt die Tatsache, dass jeweils ein geeignetes Darstellungsmodul für das CMS geschrieben werden muss. Ist dies noch mit Geld und Zeit zu bewältigen, gerät man mit Im-/ Exportläufen bei ausreichend großen Datenmengen zudem noch in Zeitprobleme. Und diese führen im einfachsten Fall nur zur falschen Anzeige auf den Webseiten. Bei Preisänderungen sieht das bereits anders aus. Sie müssen schnellstmöglich übertragen werden. Fehlende oder gar falsche Angaben könnten rechtliche Probleme nach sich ziehen. Ebenfalls unmöglich bleibt zumeist eine korrekte Verfügbarkeitsanzeige. Nur der echte Online-Zugriff eröffnet diesen Weg.

Das Grundproblem

Die Idee ist einfach und bestechend, birgt aber eine Menge Probleme. Sowohl bei der Java Virtual Maschine (JVM) als auch bei der PHP-Ausführungsumgebung handelt es sich um zwei komplett unterschiedliche Stücke Software. Beide laufen als Prozess bzw. Dienst im jeweiligen Betriebssystem und definieren die bekannten Schnittstellen für ihre jeweiligen Welten. Gerade PHP kann hier nicht glänzen. Neben STDOUT und den Webserver-Integrationen für bspw. Apaches HTTPD bzw. den Internet Information Server (IIS) von Microsoft gibt es keine standardisierten oder gar remotefähigen Objekt-Schnittstellen. Will man also beide Welten dazu bewegen, miteinander zu reden, dann müssen geeignete Zwischenstücke her, welche diese Hürde überbrücken. Diese setzen auf der Basis von einfachen Schnittstellen beider Prozesse an und übernehmen neben dem Handling der rudimentären Kommunikationswege auch das Ver- und Entpacken von Objekten bei der Interprozesskommunikation. Dies geschieht idealerweise für den Entwickler vollständig unbemerkt. Benutzbar wird das Zwischenstück durch entsprechende Programmierschnittstellen (APIs).

Eingebautes

Klassische Problemstellungen verlangen nach klassischen Lösungen. Seit PHP 4 gibt es die Java Extensions. Sie nutzen das Object Overloading von PHP um auf Java Klassen zuzugreifen. Wird damit aus PHP heraus eine Java Methode an einem Objekt aufgerufen, dann wird zuerst per Java Native Interface (JNI) eine Java Virtual Machine (JVM) erzeugt. Dann wird der Aufruf ausgeführt. Der Rückgabewert kann dann direkt als PHP Objekt in einer Klasse oder PHP-Seite angezeigt werden. Bei den Java Extensions handelt es sich um einen Teil der PECL (PHP Extension Community Library). Als solches muss dieses separat heruntergeladen und konfiguriert werden. Ein nicht ganz triviales Unterfangen. Berichte in verschiedenen Internetforen deuten zudem darauf hin, dass es sich nicht um eine sonderlich stabile Lösung handelt. Vielleicht auch ein Grund dafür, dass die Extension als experimental gekennzeichnet ist. Darüber hinaus ist die Systemarchitektur alles andere als Ideal. Grade bei Systemen unter Last bleibt zu vermuten, dass deutliche Probleme auftauchen. Schließlich wird schlimmstenfalls pro Request eine komplett neue JVM gestartet. Instanzpooling oder andere Wiederverwertung findet hierbei nicht statt. Viele Gründe, die einen Einsatz dieser Lösung in Frage stellen.

Abb. 1: Zugriff auf Java Objekte per Java Extensions

Basierend auf den Java Extensions gibt es noch den PHP4-Servlet-SAPI-Ansatz. Hierbei wird allerdings nicht Java in PHP eingebaut, sondern andersherum. Genauer gesagt wird einem Webcontainer (bspw. Apache Tomcat) eine PHP-Ablaufumgebung per Servlet eingebaut. Wird eine PHP-Seite angefragt, wird der PHP-Prozessor aufgerufen und die Rückgabe entsprechend dargestellt. Grundsätzlich verspricht dieser Ansatz eine bessere Stabilität und Performance als der vorige. Dies vor allem aus dem Grund, dass die Servlet Engine sich um das Pooling und die Wiederverwendung der doch recht schwergewichtigen JVM und ihrer Threads kümmert. Lediglich der schlankere PHP-Kern wird bei Bedarf geladen und als Quellcode ausgeführt. Für beide eingebauten Varianten finden sich Pro- und Contra-Stimmen in diversen Foren und Artikeln. Für produktive Umgebungen mögen beide Ansätze daher nur nach sorgfältiger Abwägung aller Vor- und Nachteile eine Alternative sein.

Standardisiertes

Der geneigte Java-Entwickler mag den Kopf schütteln über die ersten beiden Integrationsvorschläge. Weiß man doch, dass mit Java 6 der JSR 223 umgesetzt wurde, das sog. Scripting API. Hier wird ein definierter Weg zur Einbindung von Scriptsprachen in die Java-Welt definiert. Versteht man PHP als Scriptsprache, dann sollte es auch eine sogenannte Engine für PHP geben. Auch wenn man beim Scripting-Projekt bei Sun nicht direkt fündig wird, so finden sich doch zumindest zwei Produkte, welche die Scripting API für PHP implementieren: Zum einen die PHP/Java Bridge auf Sourceforge und zum anderen die native Java-Implementierung von PHP mit dem Namen Quercus von Caucho. Die Verwendung von PHP-Scripten innerhalb von Java ist damit ein Vierzeiler geworden:

ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine phpEngine = m.getEngineByExtension("php");
ScriptContext context = phpEngine.getContext();
Object php2javaResult = phpEngine.eval("",context);

Damit kann man als Java-Entwickler auf recht einfache Weise die Rückgabewerte von beliebigen PHP-Methoden und -klassen in die eigene Arbeit integrieren. Dennoch bleibt der Weg andersherum erst einmal verschlossen. Auch ist die Scripting Engine selber nicht in der Lage, komplette PHP-Dateien und -klassen in einem Java-Applikationsserver auszuführen. Man kann also auch mit ihrer Hilfe nicht einfach eine PHP-Anwendung in einem JEE-Applikationsserver deployen. Dafür benötigt man noch ein wenig Drumherum. Dazu später mehr.

Abb. 2: JSR-233 konforme Einbindung von PHP als Scripting Engine

Ebenfalls zu den nativen Möglichkeiten kann man sicherlich die Interaktion der beiden Technologien mithilfe von Web Services zählen, eher eine lose Koppelung denn eine enge Zusammenarbeit der beiden Welten. Nachdem Enterprise Java ohne Probleme mit Web Services klar kommt, muss man nur auf PHP-Seiten noch ein paar Dinge einbauen. Verfügbar sind hier etliche Webservice Frameworks, welche sowohl Client- als auch Server-Implementierungen bereitstellen. Stolperstein auf diesem Weg ist ganz klar die Tatsache, dass auf beiden Seiten entsprechende Schnittstellen geschaffen und Übereinkünfte bezüglich der Zusammenarbeit getroffen werden müssen. Der Gewinn bei der Verwendung von Web Services liegt sicherlich bei einer grundsätzlich etablierten und stabilen Lösung – auf keiner der beiden Seiten ist man gezwungen, native Anteile einzusetzen. Die technischen Integrationsansätze, welche im Folgenden noch vorgestellt werden, haben allerdings einen deutlich tieferen Ansatz.

Brücken

Die reine Implementierung des JSR 223 bringt für Java-Entwickler zwar die PHP-Welt näher, umgekehrt bleiben die PHP-Entwickler aber bisher noch ohne nennenswerte Unterstützung. Dieses Manko wollen die Brücken beheben. Neben der bereits erwähnten PHP/Java Bridge gibt es noch eine kommerzielle Alternative von Zend. Beide Lösungen sind in der Lage, von PHP aus auf Plain Old Java Objects (POJOs) und auf andere Java- und Java-Enterprise-Edition (JEE)-Komponenten (bspw. EJB, Connections, JMS, etc.) zuzugreifen. Die PHP/Java Bridge implementiert zwei verschiedene Zugriffswege zwischen den Welten. Zum einen eine native in PHP geschriebene Java-Brücke und zum anderen ein in C geschriebenes PHP-Erweiterungsmodul (für Versionen >=4.3.2). Die native Implementierung ist extrem einfach in der Verwendung. Es müssen lediglich die relevanten PHP-Klassen auf den Webserver kopiert werden. Danach steht mit folgenden Sourcecodeschnipsel direkt der Zugriff auf Java-Klassen zur Verfügung:

Zur Ausführung benötigt diese Variante keinerlei nativen Code (.so oder .dll – Dateien) auf dem System. Großes Manko hierbei: Im Gegensatz zum in C geschriebenen Modul ist diese Ausführungsvariante ungefähr zehnmal so langsam. Das in C geschriebene Modul muss vergleichsweise schwer konfiguriert werden. Neben dem JavaBridge.jar muss noch eine spezielle php_java.dll im PHP-Erweiterungsordner (<drive>/php/ext) landen. Natürlich muss diese auch in der PHP-Konfiguration (php.ini) entsprechend registriert werden. Unter Linux funktioniert das alles ohne installiertes Java. Unter Windows muss ein entsprechendes Java Development Kit (JDK) installiert sein. Erst im Anschluss daran ist das Modul einsatzbereit und kann beispielsweise folgenden Code ausführen:

getProperty('java.version'); 
?>

Besonders interessant ist die Tatsache, dass die PHP / Java Bridge keine Verwendung vom Java Navtive Interface (JNI) macht. Nicht unterschlagen werden soll die Tatsache, dass in dem Paket noch viel mehr steckt. Neben den zwei Brücken und der Scripting Engine gibt es auch eine MONO / .NET-Brücke. Auch kann man mithilfe eines Webarchives (JavaBridge.war) die komplette PHP-Funktionalität nach Java bringen. Für detailliertere Informationen hält die Projektwebseite für den interessierten Entwickler viele gute Informationen bereit.

Abb. 3: Einbindung der Java Bridge als Servlet

Einen kommerziellen Mitbewerber bei den Brücken stellt Zend dar. Im Rahmen der PHP-Plattform wird der sogenannte Integration Server ausgeliefert. Neben einer Eclipse Birt Integration findet man hier auch die Java Integration Bridge. Schaut man sich auf den Produktwebseiten um, dann findet man allerdings nicht viele Informationen dazu. Erst der kostenlose Download nach der Registrierung bringt einem die Details näher. Allerdings muss man dafür schon einiges tun. Will man unter Windows ein paar Gehversuche wagen, benötigt man erst einmal den Zend PHP Core. Dieser steht auf den Webseiten von Zend zum Download bereit und hat gut 42MB. Danach ist noch die Zend-Plattform fällig. Von ihr gibt es lediglich eine 30tägige Testversion. Dieser Download schlägt nochmal mit knapp 54 MB zu. Einzige Voraussetzungen zur Installation sind ein installierter Apache HTTPD (bzw. IIS unter Windows) und auf Wunsch eine MySQL-Datenbank. Beides kann auch direkt über den Core Installer mit installiert werden. Mit der Plattform wird ein sogenanntes Java Middleware Module (JavaMW) ausgeliefert. Dieses folgt der Standard PHP Java API. Für den Entwickler bedeutet dies also zuerst einmal kein Umlernen. Programmatisch sieht der Zugriff also genauso aus wie bei der modulbasierten Open-Source-Lösung (s.o.). Am Beispiel eines Zugriffs auf ein EJB mit dem Namen Trader im Weblogic Server kann das dann folgendermaßen aussehen:

$env = array (
	'java.naming.factory.initial' => 'weblogic.jndi.WLInitialContextFactory',
	'java.naming.provider.url' => 't3://localhost7001'
	);
$context = new Java('javax.naming.InitialContext', $env);
$home = $context->lookup('TraderHome');

Hier ist allerdings das Vorhandensein der wls-api.jar-Datei im System Classpath vor dem Starten des Apache HTTPD eine unverzichtbare Bedingung. Technisch bedient man sich zur Umsetzung der Kommunikation einiger Helferchen. Sowohl auf PHP (PHP-side Bridge)- als auch Java (Java-side Bridge)-Seite wird eine Komponente installiert. Diese Komponente übernimmt das Ein- und Auspacken der jeweiligen Objekte. Wird aus einer PHP-Anwendung heraus ein Java-Objekt über die Brücke angefordert, erstellt die PHP-Komponente ein Proxy-Objekt. Um Java-Instanzen wiederverwenden zu können und ein effektiveres Handling zu gewährleisten, startet man nicht einfach eine beliebige JVM und konfiguriert PHP zum Zugriff darauf, sondern es wird ein kompletter Java-Dienst auf dem System gestartet. Von diesem können sowohl Port als auch maximal verfügbare Prozesse konfiguriert werden.

Abb. 4: Schematische Darstellung der Zend PHP/Java Bridge

Soll via Bridge auf einen Java EE-Applikationsserver zugegriffen werden, wird dies per Remote Method Invocation (RMI) erledigt. Manko hier: Es kann nur auf remotefähige Objekte zugegriffen werden. In Sachen Performance profitiert dieser Weg also nicht von bereits im Java-Standard verankerten Optimierungen (EJB Local Interfaces). Nach Herstellerangaben wird an dieser Einschränkung aber aktuell gearbeitet. Zuletzt sei noch erwähnt, dass Zend zwar zusammen mit Sun den bereits genannten JSR 223 ins Leben gerufen hat, es aber bisher keine offizielle PHP-Engine-Implementierung von Zend für Java gibt.

Native Implementierung

Wer mit Standards, Eingebautem oder mit Brücken noch nicht zurechtkommt, dem bleibt eine letzte Möglichkeit. Neben der offiziellen PHP-Distribution gibt es tatsächlich eine komplett freie (auf der GPL basierende) Implementierung von PHP welche in Java geschrieben ist. Dieses Wunderwerk kommt vom Hersteller des Applikationsservers Resin, der Firma Caucho, und hört auf den Namen Quercus. Einen kurzen Blick darauf konnte man bei den Scripting-API-Implementierungen schon werfen. Der tatsächliche Mehrwert liegt aber bei den weiteren Funktionen, welche das komplette Quercus-Paket bereitstellt. Dazu zählt ein Servlet Wrapper für PHP-Aufrufe und die komplette Konfiguration der PHP-Instanz innerhalb vom jeweils verwendeten Webcontainer. Das Quercus-Paket kann als separate Webapplikation (.war-Datei) heruntergeladen werden. Nach dem Auspacken ist diese dann nur noch in das entsprechende Verzeichnis eines beliebigen Webcontainers zu schieben und schon steht ein halbwegs aktuelles PHP 5.2.0 unter Java zur Verfügung. Will man PHP-Funktionalität für vorhandene Java-Anwendungen zur Verfügung stellen, ist das ebenfalls denkbar einfach. Zwei Java-Bibliotheken sind in WEB-INF/lib zu kopieren und das PHP Servlet in der web.xml zu registrieren. Das war es schon.

PHPServlet
        com.caucho.quercus.servlet.QuercusServletPHPServlet*.php

Aber auch hier ist nicht alles so einfach wie es aussieht. Zwar stehen schon eine Menge PHP-Module für Quercus zur Verfügung (darunter APC, iconv, GD, gettext, JSON, MySQL, Oracle, PDF, und Postgres) aber den kompletten PHP-Modulumfang deckt es noch nicht ab. Allerdings reicht es schon für viele bekannte PHP-basierte Anwendungen. So zum Beispiel DokuWiki, Drupal, Gallery2, Joomla, Mambo, Mantis, MediaWiki, Phorum, phpBB, phpMyAdmin, PHP-Nuke, WordPress und XOOPS. Die frei erhältliche Version hat aber leider ein riesiges Manko. Datenbankzugriffe können nur per Java Naming and Directory Interface (JNDI) ausgeführt werden. Der normale PHP-Zugriffsweg funktioniert nur bei der lizenzpflichtigen Professional Version.

  // PHP DB Zugriff
  //mysql_connect($host, $username, $password, $dbname);
  // JNDI Zugriff
  mysql_connect("java:comp/env/jdbc/myDatabaseName");

Ebenfalls ein Schmankerl, in dessen Genuss nur die Besitzer einer Professional Lizenz kommen: Quercus kann PHP-Quellen nicht nur zur Laufzeit interpretieren, sondern auf Wunsch auch vorkompilieren. Für produktive Umgebungen sicherlich ein Performancegewinn.

Die Qual der Wahl

Abschließend mag man von der Menge der verfügbaren Integrationsansätze erschlagen sein. Dass es dann doch so viele geworden sind, ist durchaus überraschend. Es zeigt aber vor allem, dass es einen Bedarf bei der Zusammenarbeit beider Technologien gibt. Nicht zuletzt wird dieses auch durch die zunehmende Präsenz des Themas in den Medien belegt. Zur Entscheidung für den richtigen Weg kann man sicherlich keine pauschalen Aussagen treffen. Zuerst muss man sich darüber im Klaren sein, welche Technologie durch eine andere ergänzt werden soll. Wird innerhalb von PHP-Webseiten gelegentlich Java-Funktionalität benötigt, sieht eine optimale Architektur grundlegend anders aus, als wenn eine Java-Webanwendung um PHP-Teile erweitert werden soll.

Das am häufigsten anzutreffende Szenario wird vermutlich das etablierte Java Backend mit Geschäftsdaten und die agile und moderne PHP-Weboberfläche sein. Auf dieses Szenario wird man vermutlich nur bei bestimmten Kunden treffen, die neben der reinen Technologieentscheidung auch andere strategische Belange berücksichtigen müssen oder wollen. Grade dort kann aber eine Produktlösung mit Support und Professional Services punkten. Als einzige Alternative bleibt hier die Java-Integration von Zend. Direkt dahinter folgt das PHP/Java Bridge-Projekt auf Sourceforge. Durch die Unterstützung von PHP und Java wird hier jeglicher Kommunikationsbedarf in beide Richtungen abgedeckt. Noch einfacher kann dann eigentlich nur noch eine Kommunikation über offene Standards (XMLRPC/SOAP) sein. Dafür bedarf es dann auch zumeist keiner neuen Komponente in der Architektur.

Die Technik von PHP

Um eine PHP-Datei im Rahmen einer Webanwendung ausführen zu können, benötigt man ein System, das mit den in der Sourcecode Datei enthaltenen Anweisungen umgehen kann. Normale Webserver sind dazu nicht in der Lage. Sie bieten aber eine Schnittstelle (beispielsweise ISAPI oder CGI) für die Interpreter an. Sobald ein Webserver eine entsprechend registrierte Datei (bsp.: *.php) ausliefern soll, wird diese von einem Serverdaemon bzw. Serverdienst (z. B. Apache oder IIS) zuerst an den Interpreter übergeben.

Per stdout/stdin-Integration werden dabei sowohl die Sourcen an den Interpreter als auch das Ergebnis zurück an den Serverdienst gegeben. Die Ausführungsgeschwindigkeit ist hierbei allerdings nicht sonderlich hoch. Um diesem Problem zu begegnen, wurde dieser Integrationsansatz zunehmend durch Modulintegration ersetzt. Somit finden sich heute für den Apache-Webserver diverse Module zur Integration von Scriptsprachen. Mod_PHP ist für die Einbindung des PHP Interpreters zuständig.

Markus Eisele arbeitet seit mehr als fünf Jahren als IT-Architekt und freiberuflicher Autor. Seine Themenschwerpunkte liegen bei JEE-Projekten, Softwarearchitekturen, Softwarequalität, Frontendintegration und modernen Oberflächentechnologien.

Geschrieben von
Markus Eisele
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.