Running a JSP as an Azure Function

In our previous blog entry we demonstrated you can run a Servlet as an Azure function. Can we do the same with a JSP? The answer to that question is YES. It is a little bit more involving as Azure Functions by default uses just the JRE and for JSPs you need the JDK.

Below is the quick recipe to get this to work!

The code below is the 'Hello World' JSP


<%@page contentType="text/html" pageEncoding="UTF-8" session="false"%>
<html>
    <head></head>
    <body>
        <h1>Hello World</h1>
        And today's date is <%= new java.util.Date() %>
    </body>
</html>
        

The code below is the Azure Function dispatching to the 'Hello World' JSP

            
public class HelloWorldFunction {

    @FunctionName("/helloworld")
    public HttpResponseMessage run(
            @HttpTrigger(
                    name = "request",
                    methods = {HttpMethod.GET},
                    authLevel = AuthorizationLevel.FUNCTION
            ) HttpRequestMessage<Optional<String>> request,
            final ExecutionContext context) {

        NanoRequest nanoRequest = new NanoRequestBuilder()
                .method("GET")
                .servletPath("/helloworld.jsp")
                .build();

        ByteArrayOutputStream nanoOutputStream = new ByteArrayOutputStream();
        NanoResponse nanoResponse = new NanoResponseBuilder()
                .outputStream(nanoOutputStream)
                .build();

        String body = null;

        File[] libFiles = new File("lib").listFiles();
        StringBuilder classpath = new StringBuilder();
        if (libFiles != null) {
            for (int i = 0; i < libFiles.length; i++) {
                classpath.append(libFiles[i].getAbsolutePath());
                if (i + 1 != libFiles.length) {
                    classpath.append(File.pathSeparatorChar);
                }
            }
        }
        try {
            NanoPiranha piranha = new NanoPiranhaBuilder()
                    .directoryResource("webapp")
                    .servlet("JSP Servlet", new JspServlet())
                    .servletInitParam("JSP Servlet", "classpath", classpath.toString())
                    .servletInitParam("JSP Servlet", "compilerSourceVM", "1.8")
                    .servletInitParam("JSP Servlet", "compilerTargetVM", "1.8")
                    .servletInitParam("JSP Servlet", "fork", "false")
                    .build();
            piranha.service(nanoRequest, nanoResponse);
        } catch (IOException | ServletException e) {
            body = e.getMessage();
        }

        if (body == null) {
            body = nanoOutputStream.toString();
        }

        return request.createResponseBuilder(HttpStatus.OK).
                header("Content-Type", "text/html").
                body(body).
                build();
    }
}
        

Then deploy the Azure function.

If you try it out now it will tell you it needs a JDK instead of the JRE.

So we will need to upload a JDK we can use.

To do so you will use Kudu to upload the zip file containing a Windows 64-bit version of the JDK.

Then you will also need to create 2 AppSettings like the ones below:

languageWorkers:java:defaultExecutablePath D:\Home\jdk8u242-b08\bin\java
WEBSITE_USE_PLACEHOLDER 0

Make sure the path above corresponds to the location of the java.exe of the JDK you previously uploaded.

See Customize JRE used by Azure Functions for more information.

This is all made possible by the Piranha Nano runtime, which is part of the Piranha Cloud project that delivers you with a highly composable cloud runtime.

A zip file that contains everything you need is available here

Posted February 17th, 2020

Up