Monday, December 11, 2006

PHP on an OSGi Framework?

Last week (2006/12/08) the OSGi Alliance had a webinar for their members. Last month, Susan Schwarze from marketing had asked me very sweetly to provide a demonstration for this webinar. After some soul searching I had proposed to make a demonstration using the OSGi Framework in a multi language setting. The scenario of the demo was simple: show how to start a framework, get some basic bundles installed, install some applications from the OSGi Bundle Repository (OBR) to show it all works, and then as grande finale, install a PHP interpreter and port a PHP Wiki to an OSGi bundle in real time. And this all must happen in 20 minutes.

The most interesting part of the demo was obviously the PHP part. I always thought that having a PHP interpreter on an OSGi framework would be really cool (However, hard this is to explain to my kids and wife)! With an OSGi based PHP interpreter you can deploy PHP applications as OSGi bundles. This is attractive to companies that today use PHP on remote servers as well as device vendors that want to design their web sites in PHP.

The demo was not the first time I had come up with PHP. I had searched the web for a PHP interpreter written in Java already several times but I had never found one until I discussed this demo with BJ Hargrave. He mentioned that there was an open source project/company doing a Java based PHP interpreter: Quercus. The interpreter is a part in the bigger Resin webserver. With my usual optimism, I though: “How hard can it be to port this interpreter to an OSGi bundle?”

Well, hard.

It started all very hopeful because there was a class Quercus Servlet and the OSGi HttpServer supports servlets very well. Unfortunately, the Quercus Servlet was assuming it ran inside the Resin server, making it impossible to use with another web server. Writing my own servlet was luckily only a few hours. Unfortunately, I could not resist simplifying the Quercus Servlet which added a few unnecessary hours to undo these simplifications when I understood why the complications were there in the first place.

The next problem I ran into was the file system. Normally PHP assumes that all the sources are in the file system and in our case the files had to come from a bundle. Quercus/Resin supported a virtual file system but it took some time to find out how you could provide a new source for files. It turned out you had to write your own Path sub-class and then set the root path to an instance of your type. All other files are then relative to that root. Reading was very easy to program, I just mapped all the read primitives to the resource access in the bundle. However, writing was a lot harder. At first, I decided to allow the bundle that carries the PHP files to specify its URI and a set of writable directories. That is, I architected the following headers:

PHP-Path: /mywiki
PHP-Data config, data, wiki.d

I got this to work but ran into the problem that some PHP programs actually re-write their own source files. Having special writable directories forced me to modify several PHP programs, obviously not a desirable architecture. Then it suddenly hit me (under the shower!) that I could just do the rather standard technique of copy-on-write. So I got rid of the PHP-Data header altogether. A read would now always first look on the file system (actually the bundle’s data directory) and then in the bundle’s resources. A bit tricky was the handling of directories; they should be automatically created when you wrote a file that also resided in the jar. After this (awfully late) insight, it became quite easy and I could use several PHP programs from the net without any modifications. This worked so well that I could show off this model with a real functioning Wiki that was wrapped in a bundle directly from the Internet!

However, I wanted one more splash and I found this splash in the Quercus modules. The Quercus interpreter was designed to be very modular; all its commands were written in separate modules which were loaded at startup. This model was too tantalizing to not use it to show off the dynamic capabilities of the OSGi Framework. Would it not be impressive if you could install a new Quercus Module on the fly as a bundle (Again, an excitement my family rarely shares)? So I decided to create a Service Tracker that listened to Quercus Module services. Those service objects were then added/removed as a module to the Quercus interpreter. I had to write a new remove function inside the interpreter because, like so many programs, it had no concept of modules that could go away.

Quercus Modules could now be written as OSGi bundles. This turned out very simple to do because bnd (a program/plugin that creates bundles from a recipe) supports declarative services as well. I could just create a small bnd file that builds the bundle and indicates what class should be registered under the QuercusModule interface. Like:

Private-Package: com.caucho.quercus.lib.zip
Import-Package: *
Service-Component: com.caucho.quercus.lib.zip.ZipModule;
provide:=com.caucho.quercus.module.QuercusModule

I had decided early on that I did not want to do the demo live. I guess I am becoming chicken at my old age; the chance that something fails is just a bit too high. I therefore used Instant Demo. This application can record everything that happens in a window. You can edit this recording and provide sound as well. Instant Demo then converts the total set of files to a flash file so you can play it in any browser. I must say, using such a program is a humbling experience because every little error requires a restart. It was painful to have to repeat the same actions over and over again just to get it right.

Anyway, after a lot of hard work I finally succeeded in making four short movies about this demo. If you are interested, download this presentation and play it. Let me know if you think we should have more of such demos. Should we also do this for JRuby and run Ruby-On-Rails applications on OSGi Frameworks? Hmm, sounds cool!

Peter Kriens

P.S. The Quercus interpreter is not available because the code is not industrialized. It really worked for a demo (nothing was faked) but it requires more work to harden it for real use. However, I will contact the resin people to see if they like to modularize their webserver. Their web server screams for OSGi technology!

4 comments:

  1. Very interesting reading. I didn't knew the Quercus PHP compiler, and this is also a very interesting project ! Will have a serious look at all this tomorrow :)

    I remember when I used to develop mostly with PHP, and few with Java, PHP3 and PHP4 were supporting a basic Java bridging (but very inefficient and unstable) and PHP was able to be run inside a servlet container like Tomcat. I get it work under Tomcat.

    I just downloaded PHP5 though and saw that Java support and Servlet support have totally been removed from this release.
    But there are still people trying :
    http://mail-archives.apache.org/mod_mbox/tomcat-users/200603.mbox/%3C4427467D.6060205@erols.com%3E

    Seems like he is using PHP 4 considering the Zend version.
    I don't know why the PHP team removed the servlet API support, but it would have been also a good way to make PHP runing inside OSGi.

    New I'm eager to see you make JRuby and Rails work under OSGi ! ;-)

    ReplyDelete
  2. great, i was looking for something like this. Unfortunately you webinar is not more accessible.

    I am looking forward to deploy php as a service in OSGi. Can you please send me the webinar.

    Since this article is very old, I am sure a lot must have gone into this now. Request you to provide some insight on it today.

    Regards
    Arpit Mittal

    ReplyDelete
  3. I'm a developer who is currently trying to do what you discussed in this blog, encapsulate a php module into an OSGi bundle. I've been having trouble finding any documentation on how to do this and the powerpoint you referenced here is not available for download. Can you reupload it, and maybe provide any insight on advances in the technology (if you know of any)? Thanks!

    ReplyDelete
  4. Please update the outdated links.

    ReplyDelete