The JWSGI interface

Note

JWSGI is not a standard. Yet. If you like JWSGI, why not send an RFC to the uWSGI mailing list. We have no specific interest in a standard, but who knows…

JWSGI is a port of the WSGI/PSGI/Rack way of thinking for Java.

If, for some obscure reason, you’d feel like developing apps with JVM languagesand you don’t feel like deploying a huge servlet stack, JWSGI should be up youralley.

It is a very simple protocol: you call a public method that takes a HashMapas its sole argument. This HashMap contains CGI style variables andjwsgi.input containing a Java InputStream object.

The function has to returns an array of 3 Objects:

  • status (java.lang.Integer) (example: 200)
  • headers (HashMap) (example: {“Content-type”: “text/html”, “Server”:“uWSGI”, “Foo”: [“one”,”two”]})
  • body (may be a String, an array of Strings, a File or an InputStreamobject)

Example

A simple JWSGI app looks like this:

  1. import java.util.*;
  2. public class MyApp {
  3.  
  4. public static Object[] application(HashMap env) {
  5.  
  6. int status = 200;
  7.  
  8. HashMap<String,Object> headers = new HashMap<String,Object>();
  9. headers.put("Content-type", "text/html");
  10. // a response header can have multiple values
  11. String[] servers = {"uWSGI", "Unbit"};
  12. headers.put("Server", servers);
  13.  
  14. String body = "<h1>Hello World</h1>" + env.get("REQUEST_URI");
  15.  
  16. Object[] response = { status, headers, body };
  17.  
  18. return response;
  19. }
  20. }

How to use it ?

You need both the ‘jvm’ plugin and the ‘jwsgi’ plugin. A build profile named‘jwsgi’, is available in the project to allow a monolithic build withjvm+jwsgi:

  1. UWSGI_PROFILE=jwsgi make
  • Compile your class with javac.
  1. javac MyApp.java
  • Run uWSGI and specify the method to run (in the form class:method)
  1. ./uwsgi --socket /tmp/uwsgi.socket --plugins jvm,jwsgi --jwsgi
  2. MyApp:application --threads 40
This will run a JWSGI application on UNIX socket /tmp/uwsgi.socket with 40threads.

Reading request body

The jwsgi.input item is an uwsgi.RequestBody object (subclass ofjava/io/InputStream). You it to access the request body.

  1. import java.util.*;
  2. public class MyApp {
  3.  
  4. public static Object[] application(HashMap env) {
  5.  
  6. int status = 200;
  7.  
  8. HashMap<String,Object> headers = new HashMap<String,Object>();
  9. headers.put("Content-type", "text/plain");
  10.  
  11. int body_len = Integer.parseInt((String) env.get("CONTENT_LENGTH"));
  12. byte[] chunk = new byte[body_len];
  13.  
  14. uwsgi.RequestBody input = (uwsgi.RequestBody) env.get("jwsgi.input");
  15.  
  16. int len = input.read(chunk);
  17.  
  18. System.out.println("read " + len + " bytes");
  19.  
  20. String body = new String(chunk, 0, len);
  21.  
  22. Object[] response = { status, headers, body };
  23.  
  24. return response;
  25. }
  26. }

Pay attention to the use of read(byte[]) instead of the classicalread(). The latter inefficiently reads one byte at time, while the formerreads a larger chunk at a time.

JWSGI and Groovy

Being low-level, the JWSGI standard can be used as-is in other languagesrunning on the JVM. As an example this is a “Hello World” Groovy example:

  1. static def Object[] application(java.util.HashMap env) {
  2. def headers = ["Content-Type":"text/html", "Server":"uWSGI"]
  3. return [200, headers, "<h1>Hello World</h1"]
  4. }

One serving a static file:

  1. static def Object[] application(java.util.HashMap env) {
  2. def headers = ["Content-Type":"text/plain", "Server":"uWSGI"]
  3. return [200, headers, new File("/etc/services")]
  4. }

The second approach is very efficient as it will abuse uWSGI internalfacilities. For example if you have offloading enabled, your worker thread willbe suddenly freed. To load Groovy code, remember to compile it:

  1. groovyc Foobar.groovy

Then run it:

  1. ./uwsgi --socket /tmp/uwsgi.socket --plugins jvm,jwsgi --jwsgi Foobar:application --threads 40

JWSGI and Scala

Like Groovy, you can write JWSGI apps with Scala. You only need the entry pointfunction to use native Java objects:

  1. object HelloWorld {
  2. def application(env:java.util.HashMap[String, Object]): Array[Object] = {
  3. var headers = new java.util.HashMap[String, Object]()
  4. headers.put("Content-Type", "text/html")
  5. headers.put("Server", "uWSGI")
  6. return Array(200:java.lang.Integer, headers , "Hello World")
  7. }
  8. }

Or in a more Scala-ish way:

  1. object HelloWorld {
  2. def application(env:java.util.HashMap[String, Object]): Array[Object] = {
  3. val headers = new java.util.HashMap[String, Object]() {
  4. put("Content-Type", "text/html")
  5. put("Server", Array("uWSGI", "Unbit"))
  6. }
  7. return Array(200:java.lang.Integer, headers , "Hello World")
  8. }
  9. }

Once compiled with scalac <filename> you run like this:

  1. ./uwsgi --socket /tmp/uwsgi.socket --plugins jvm,jwsgi --jwsgi HelloWorld:application --threads 40