Sunday, September 25. 2011
Tomcat 7 and the Invoker Servlet
Some weeks ago I was on vacation and spent some days in my home town. One afternoon I was with an ex-colleague who requested my help to migrate a Tomcat application (you know, with friends like that...). In summary the application was a huge (lots of classes) and old (I think it runs right now in tomcat 4.1) servlet and JSP web app. He was trying to migrate it to a newer version of tomcat (6 or 7) but he is not a specialist in this matter.
In summary the main problem was that this application uses the Invoker Servlet which I did not even known before. It is a strange Servlet used in previous versions of tomcat which is now deprecated in version 6 and totally removed in 7. It seems that the Invoker is a dynamic servlet which allows run-time loading of other servlets based on class name. Currently it is considered evil and that is the reason for its deprecation and clean up. I thought this Servlet needed to be removed but my mate explained me that the application had dozens and dozens of servlets (and references in JPSs too) and it would be a total nightmare. So, focusing in version 6 and after some configurations changes, the application started successfully in tomcat 6 and it begun to work using the Invoker Servlet. My friend still had (and has) a lot of work to do but he needed this little push to start on. Then he kindly paid the beers I deserved.
But turning the issue over in my mind later I decided to find a direct way to replace the Invoker Servlet in tomcat 7. Obviously you can workaround the problem just getting the servlet code and putting it inside your project but, you know, this is not my way. I am going to try the following two ideas:
- In order to not change any reference to the servlets, all of them need to be mapped following the exact way Invoker does (Invoker uses the path /servlet/servlet.class.fully.qualified.name). Obviously keeping the class name in the request is not recommended in terms of security but, at least, no dynamic re-thrown and common servlet mapping is used.
- The other snag is that the application can potentially have hundreds of servlets (I know, this is crazy but I am also sure that many of you have seen an application like this at least once in your life). Besides my mate is a bit lazy, so I am sure he is not going to check all the links to find which are the servlets to map in the configuration file. This way my idea is using new Servlet 3.0 programmatic registration to search, create and map them. Only servlets under some specified packages will be checked.
It is important to understand that this is not a good solution (it is still evil although a bit less). Defining and mapping all your servlets in the web.xml is the best solution and never use the qualified class name as the map name. This workaround needs to be understand as a temporary step that let you use last versions of tomcat with Invoker Servlet applications (huge ones, in little ones just map your servlets).
TOMCAT6
Once everything is explained I am going to deploy an Invoker Servlet application inside tomcat 6 and then move it to tomcat 7. In order to setup the Invoker inside version 6 you need to uncomment invoker definition and mapping in ${TOMCAT6_DIR}/conf/web.xml:
<servlet> <servlet-name>invoker</servlet-name> <servlet-class> org.apache.catalina.servlets.InvokerServlet </servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>invoker</servlet-name> <url-pattern>/servlet/*</url-pattern> </servlet-mapping>
The context needs to be defined as privileged (I think tomcat guys do that in order to make clear that this is evil) inside the ${TOMCAT6_DIR}/conf/context.xml. You just need to add privileged="true" to the context tag:
<Context privileged="true">
Finally a simple application was deployed (here it is the netbeans project for version 6). This application has two servlets: InfoServlet.java (typical servlet that shows some request variables like url, path, cookies, headers, parameters and so on) and HelloServlet.java (a servlet that forwards to a JSP and just says hello). Besides I copied both classes in three different packages (sample.invoker.servlet, sample.invoker.other and sample.invoker.another), I like to test Invoker against several packages and servlet classes.
TOMCAT7
Tomcat 7 supports new Servlet standard version 3.0 and the main idea is to programmatically register the servlets found inside some pre-defined packages. All this code has been placed in a context listener (see the servlet 3.0 link I presented before). The listener needs to be added in the web.xml configuration file:
<listener> <listener-class> sample.invoker.ctxlistener.InvokerLoadListener </listener-class> </listener>
In order to search for classes that extends HttpServlet (and implements ContainerServlet, an interface which is needed by the Invoker Servlet, I try to be as restrictive as possible) I followed the idea presented by vtatai in this post. But I extended it to search through files and jars. Basically the code gets the resources with the specified package using the ClassLoader and then only those which are file: or jar: are inspected, reflection is used to check if the class is a servlet. Using an init parameter in the web.xml you can specify one or more package names to take into account (only servlets under these packages will be registered).
<context-param> <param-name>invoker.packages</param-name> <param-value> sample.invoker.servlet, sample.invoker.other, sample.invoker.another </param-value> <description>List of packages to check for servlets (comma separated)</description> </context-param>The final part performs the dynamic registration. The complete InvokerLoadListener.java and netbeans project for tomcat 7 can be downloaded.
Here you see my video. I start tomcat 6 and execute InfoServlet and HelloServlet (different packages). Then I stop version 6 and start the version 7 (I did not change ports to have both tomcats running). Executing the same servlets you can check that both results are exactly the same.
Today entry tries to explain how to workaround the Tomcat Invoker Servlet in new version 7 (this last version has removed the servlet because of its evilness). The solution uses Servlet 3.0 API, class loaders and reflection to dynamically register all the servlets in the application. It is a bit less insecure (there is no redirection, standard mapping and only servlets under specified packages are included) and, more important, it works inside Tomcat 7. Of course the context listener that searches for servlets can take some time to find all of them, but if your servlets are located in a few packages it is not so much, besides think this code is only executed once at startup.
David, you owe me another beer!
Tuesday, September 13. 2011
Adding Sharing Buttons to the Entries
The other day I read some recommendations about how you can improve your blog impact (I am sorry but I cannot find the link again and besides I think it was in Spanish). One of the main advice was adding the typical sharing buttons to your blog entries (you know, the buttons to share via digg, reddit, facebook like or tweet this, I am sure you have seen these buttons dozens of times). I am not a fun of social networks (no twitter, my facebook account was requested to be closed,...), I usually read some bookmark pages (digg, slashdot or Spanish menéame) but always anonymously, and the number of visits to the blog is merely a matter of pride. So, although it really does not matter very much, I am completely agree with that advice, anything that let you spread your entries it is clearly a good idea.
So from now on when you enter to see a single entry some links to share it will appear just after the post information and before trackbacks and comments. I have just added an AddThis toolbar after reading this blog entry. I tested nothing, as I said I have no account in any of these sites, so if you detect any problem sharing or bookmarking an entry please comment below.
Thank you all!
Thursday, September 8. 2011
Testing WebGL
One of the common topics of this blog is the HTML5 standard and its multiple new features. Today I am going to test WebGL, which is a standard specification to add 3D graphics in a browser canvas element without using any plug-in or external component (so it is not part of HTML5 itself but depends on it). Obviously this feature is deeply connected to graphic hardware acceleration because any WebGL application needs to be GPU accelerated in order to run smoothly. WebGL is a breaking new feature in the web world and another element of great controversy among browsers. If you remember, the canvas element was already commented in a previous series of this blog, but there only 2D graphics were shown.
WebGL standard is being driven by the Khronos Group and all players in the web are involved (Apple, Google, Mozilla and Opera) except Microsoft. The corporation headquartered in Redmond rejects this standard and has declared several times that IE will not support it, they consider WebGL harmful in terms of security and they are not totally wrong.
The summary of the current situation is more or less the following. Chrome (initial webGL support in version 9) and firefox (version 4 also added WebGL) support WebGL in Windows (and I think Mac OS) and it is enabled by default. Opera does not support it although there is a WebGL preview version for its version 11.50 only for windows. On Mac OS Safari was adding the support in their WebKit nightly builds but maybe in Lion WebGL is already supported (sorry but I am not a Mac OS user). There are some summaries of the supportability matrix, for example in the Khronos page or in the first chapter of this tutorial, but this is a constantly changing subject so please always re-check. Nevertheless the main problem comes in the Linux world. Here there are a lot of problems related to the implementation of many graphic drivers, firefox reported issues with Linux GPU drivers and both chrome and firefox added a gpu blacklist to disable some features (WebGL mainly) depending the driver and the OS involved. Firefox 6 and 7 are supposed to remove more and more drivers from the blacklist, same behavior is expected in the next versions of chrome, as soon as linux driver implementations became more reliable. In summary current browsers in Linux hardly support the nvidia binary blob as the only out of the box WebGL driver (at least in my case my two boxes are blacklisted, my desktop uses gallium R300 driver and my laptop classic intel stack).
After this little introduction I am going to present a quick demo of WebGL. I am very, very interested in porting my PFC project to a web version. It is incredible to me how a 12 years old project (which had to be run inside a SGI server) can now be run inside a browser. If you remember what I told in that entry, I lost my code and all the data (mesh and textures) because of a broken CD, so this implementation is only a simple demo with new and fixed data (there is a lot of room for improvement). The demo has the following features:
- A fixed height mesh is retrieved using a static json file. This file contains the starting latitude and longitude of the mesh, the number of points (rows and columns), the length or step of each side, the matrix data and a lot of configuration parameters. This mesh is not drawn completely. In OpenGL and WebGL (they are very similar) the idea is simple, all the figures are sent to be drawn and depending the perspective, camera and other elements the engine draws what is needed. But in my PFC the mesh was so big that only a part of it was sent to be drawn. I have followed the same idea in this demo.
- Basic camera management. The camera is implemented using its own axis, this way the camera can turn and move following natural keystrokes and mouse movements.
- Tile representation and painting. In the real application every satellite image was the texture for a tile mesh (50x50 points). This way the part of the mesh that corresponded to an image was painted independently (the application drew each square of mesh with the associated texture). I have implemented the same here but, in the demo, there is only one tile (a 8x8 tile) which is repeated all the time horizontally and vertically (11 times in each direction).
- Easy texture loading. A simple FIFO queue has been implemented to load and unload images. Actually this is not used in the demo cos only one image is used (there is only one tile which is repeated, so only one texture is needed and the queue is never filled).
- Basic ambient and directional light for emulating the sun (in my PFC there were more environmental effects like sky, fog,...).
- Management of the configuration parameters. I have used the new input type number which is only supported in some browsers. HTML5 is everywhere.
The whole demo is below, integrated in the entry using an iframe. It is a pity that I cannot have at my disposal the real data from my PFC (damn CD). As I said a simple pattern (only 8x8 points) is repeated all the time (11x11 tiles). This way I do not upload a lot of images to the server. How to navigate using keyboard or mouse is explained in the right part of the page.
Remember what I have said before, in order to test this example you need a modern browser if you use Windows (firefox, chrome or the Opera 11 preview but not IE9). In Linux you need firefox or chromium but usually you need to disable the black list. Debian testing packages have just been upgraded to Chromium 13 and iceweasel 5 respectively and both support WebGL. In chromium the blacklist has to be ignored starting the browser with the following option:
$ chromium --ignore-gpu-blacklist
In Firefox I have changed some webgl settings (in the about:config page):
webgl.disabled | false (default) |
webgl.force-enabled | true |
webgl.force_osmesa | false (default) |
webgl.osmesalib | /usr/lib/x86_64-linux-gnu/libOSMesa.so.6 |
webgl.prefer-native-gl | true |
webgl.shader_validator | true (default) |
webgl.verbose | true |
And the browser has to be executed with the following environment variable:
$ MOZ_GLX_IGNORE_BLACKLIST=1 iceweasel
This entry is doubtless the one that I have spent more time working on it. I was developing the JavaScript code long hours and I have to admit that I started it some time ago (last months I have been quite busy and I was never in the mood to finish it). Documentation about WebGL is very poor and thanks to this good tutorial I could start the development, but when you need something special, custom or a mix of things you usually wasted much time just trying to identify how to do it. In summary current WebGL support is quite a mess (much more in the Linux world) but it is an essential feature to move gaming to the web. When I saw that quake was available inside a browser I was totally shocked. I personally think this technology is unstoppable, no matter how buggy or insecure it was. Needless to say, flash is the current option for all of this, so WebGL should be very buggy and very insecure to be unworthy.
Long life to the web wars!
Comments