XPages to Java EE, Part 6: Dependencies

  • Jan 31, 2019

This is going to be a quick post, but I think it's useful to treat the topic of third-party dependencies on its own because of how much nicer it is with a Maven-based app than an NSF or OSGi plugin.

Historically, we've handled dependencies primarily by downloading a Jar and either plunking it in jvm/lib/ext on the server, stashing it in a Java agent or script library, or importing it into the NSF as a Jar design element for XPages. With OSGi plugins, that remained the simplest way to do it too: just drop the Jar into the plugin and add it to the bundle classpath.

The two big problems with those approaches are that they rely on having just "some file" deployed around with no version management and they also don't include any source. As anyone who's tried to figure out some behavior inside the XPages stack knows, not having the source for your dependencies is a real pain in the ass.

Building a normal Maven (or Gradle) project, though, means dependency management becomes much easier and we get source support "for free".

Eclipse Prep

Before we begin, open your Eclipse preferences and go to the "Maven" category. There, turn on "Download Artifact Sources" and "Download Artifact Javadoc":

Eclipse's Maven preferences

This will cause Eclipse to automatically use Maven's ability to download associated source and Javadoc for dependencies (referred to "artifacts" in Maven parlance). You can do this manually after the fact or via the command line, but it's nice to have it on by default.

Adding the Dependency

For our example, we'll bring in a Markdown processor. Open the project's pom.xml file and set the dependencies block to this:

	<dependencies>
		<dependency>
			<groupId>javax</groupId>
			<artifactId>javaee-api</artifactId>
			<version>8.0</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>com.atlassian.commonmark</groupId>
			<artifactId>commonmark</artifactId>
			<version>0.12.0</version>
		</dependency>
	</dependencies>

Save the file and that's it - Eclipse will automatically fetch the Jar and add it to the project's build path:

Eclipse's Maven Dependencies library

Note that the two dependencies in the pom.xml have a key difference: the Java EE API dependency is marked as <scope>provided</scope> while the new dependency has no specified scope (technically making it compile scoped). This determines the behavior of the .war packager: a "provided" dependency is available while developing, but is not packaged with the application. This is used to indicate that you expect the runtime environment to provide this dependency for you, which a Java EE container does for the EE API. With a default/compile-scoped dependency, the Jar is included in the app's WEB-INF/lib directory, which the container knows to include in the app's runtime class path.

Using the Dependency

This section shouldn't have any surprises: now that you added the dependency, it's available for your app. Create a new class in the com.example package named MarkdownExample with this contents:

package com.example;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;

@Path("markdown")
public class MarkdownExample {
	@GET
	@Produces(MediaType.TEXT_HTML)
	public String get() {
		Parser markdown = Parser.builder().build();
		Node parsed = markdown.parse("# Hello\n\nWorld"); //$NON-NLS-1$

		HtmlRenderer markdownHtml = HtmlRenderer.builder().build();
		return markdownHtml.render(parsed);
	}
}

As before, run a Maven Build with the goals clean install tomee:run and then visit http://localhost:9091/javaeetutorial/resources/markdown. If all goes well, you should see the HTML output:

Markdown HTML output

Updating the Dependency

Beyond just automatically bringing in dependencies, Maven gives us a raft of abilities to manage them. Do a Run As -> Maven Build... on the project and this time set the goals to versions:display-dependency-updates This will run for a bit to look up all of your dependencies to find if any are out of date. After running, you should see something like this near the bottom (the versions may differ based on when you do this):

[INFO] The following dependencies in Dependencies have newer versions:
[INFO]   com.atlassian.commonmark:commonmark ................. 0.12.0 -> 0.12.1
[INFO]   javax:javaee-api ..................................... 8.0 -> 8.0.1-b5

You can also have Maven automatically bump the versions in your pom.xml for you, but this demonstrates why I don't like to do that: the javaee-api update is to a beta version, and we have no need to move to that. There's no reason not to update our commonmark dependency, though, and so I like to run this (and the equivalent command to look for Maven plugin updates) periodically.

Next Steps

After these basics, the next steps are going to have to involve making some choices that won't apply as generally as the steps so far. Data storage and user authentication are going to vary greatly from environment to environment, but I'll aim to show the current ways to do those in a mostly-agnostic fashion.

XPages to Java EE, Part 5: Web Pages

  • Jan 24, 2019

Once upon a time, web pages were easy: you'd write some HTML directly or, if you're fancy, use some Server Side Includes or PHP. Now, though, it's a rat's nest of decisions and stacks - fortunately for me, going into the pros and cons of each approach is beyond the scope of this series. Suffice it to say that Java EE can cover your needs whatever approach you take: it can do basic dynamic HTML generation, run server-persisted frameworks like JSF, and work splendidly as a backend for a client JS app thanks to JAX-RS.

For this post, I'm going to stick to some basics: a JSP page pulling in values from a translation resource bundle. This should provide a nice introduction to a couple more core technologies that will come in handy in app development, in particular CDI.

Translation File

Localization and internationalization are huge topics and there are many approaches to take, both in technology and in style within individual technologies. I won't weigh in too much on that in general, but I'll keep it simple here. Using the Java ResourceBundle class, you can use a set of .properties files in your project to provide translations for different locales, as well as a default. Even though almost everything I write ends up US-English-only anyway, I like to have something like this for good practice.

Open the Java Resources node of the tutorial project, right-click on src/main/resources, and choose New -> Other:

For the type, choose "File" under the "General" category:

Set the name of the file to "translation.properties":

In the new file, set the contents to this (or feel free to customize at will):

_lang=en
appTitle=Java EE Tutorial
welcome=Hello, {0}

Index Page

Now, right-click on the project root and choose New -> JSP File:

If you don't see that entry in the New menu, pick Other... and do a search in that dialog for "JSP".

Name this file "index.jsp" and hit Finish:

If you hit Next >, you'll have the option to pick from some pre-made templates, which is good to know about, but we don't need it now.

Replace the new file's contents with this:

<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%>
<!DOCTYPE html>
<html lang="${translation._lang}">
	<head>
		<title>${translation.appTitle}</title>
	</head>
	<body>
		${messages.format("welcome", param.name)}
	</body>
</html>

Unlike with XPages, we're starting with bare bones here: no HTML will show up on the page unless you explicitly put it in here, either via HTML you write or via programmatic tags you bring in. The binding language, though, should be familiar: that's EL 3, which is (among other things) the current form of the expression language found in XPages. Since we're working with a JSP page, there's no such thing as a "run-time binding", so everything is the ${}-style "on page load" format. The language is also fancier nowadays, and you can see a method expression at work.

Translation Bean

So now we have the backing translation file and the front-end page using it, but we're missing the glue that connects the two. For that, we'll create some CDI managed beans.

Create a new Java class in the bean package named TranslationBean and set its contents to this:

package bean;

import java.text.MessageFormat;
import java.util.ResourceBundle;

import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;

@RequestScoped
public class TranslationBean {
	@Inject
	HttpServletRequest request;

	@Produces @Named("translation")
	public ResourceBundle getTranslation() {
		return ResourceBundle.getBundle("translation", request.getLocale()); //$NON-NLS-1$
	}
	
	@RequestScoped
	@Named("messages")
	public static class Messages {
		@Inject
		HttpServletRequest request;
		@Inject @Named("translation")
		ResourceBundle translation;
		
		public String format(String key, Object... params) {
			String message = translation.getString(key);
			return MessageFormat.format(message, params);
		}
	}
}

There are a few weird bits going on here, but some of them are direct analogues to what we do in XPages.

For starters, the @RequestScoped annotation is exactly what you might think: it marks the class as being a request-scoped managed bean, and the semantics of this are the same as in XPages, just without having to add an explicit definition like in faces-config.xml. This is paired with @Named("messages"), which defines the name of the bean as used by the JSP page.

Next up is the @Inject annotation, which really dips into the magic going behind the scenes. In a Java EE app, CDI acts as a sort of general object-management layer, and it picks up on annotations like these and sets the values of object properties based on providers. In the case of HttpServletRequest, the app has implicit knowledge of the current request, and so can inject it there - this is kind of similar to how an XPages app always has a session object implicitly available. This is also similar to "managed properties" in JSF/XPages, though it's a rare XPages app that uses those.

The part that's entirely new is the @Produces annotation. This tells CDI that a given method can churn out an object matching a specific characteristic, and we use that here for getTranslation(). Because ResourceBundle on its own doesn't have an implicit instance like HttpServletRequest does, we declare the method as producing a ResourceBundle specifically with the name "translation". This name is used both on the JSP page as a normal managed-bean name and also within the inner Messages class, which asks for the named ResourceBundle as its own property. There's actually a whole world of different qualifiers and matching patterns that can apply here, and you can also have implementation classes that are actually proxy classes created on the fly. We may deal with those eventually, but not here.

Loading It Up

As before, run the application by executing a Maven build with the goals "install tomee:run". Once it's done, you should be able to go to http://localhost:9091/javaeetutorial/?name=World and be greeted with this visual splendor:

The HTML will be pleasantly sparse:

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>Java EE Tutorial</title>
	</head>
	<body>
		Hello, World</body>
</html>

An actual application page would naturally get much more complex (for one, it shouldn't have the giant script-injection hole this one has via the direct inclusion of the query parameter), but you get the idea.

Next Steps

Next, I think that I'll show a quick example of bringing in a third-party dependency. The process for that is pretty quick, but I think it will be useful to show the mechanics and use it as an example of something that is a couple steps easier outside of Domino.

There are also a number of big topics remaining: user security, database access, and so forth. I don't know how deep I'll go into each of those, since the implementations vary so much in practice, but I think it'll be useful to at least have an example to start with.

XPages to Java EE, Part 4: Application Servers

  • Jan 23, 2019

I mentioned in the terminology post that one of the new things to get used to in Java EE is the concept of a "Servlet Container" or "Application Server", and I think that this concept is worth a bit of going in to.

In a general sense, we've been working with this concept for a good while now: Domino is an application server in several senses, and (for the most part) the NSFs are the applications it houses. It blurs the lines in a couple ways by virtue of NSFs also being data stores, but an XPages application is a pretty direct match for a .war file deployed to an application server, code-wise.

The Options

So, conceptually we have a match, but a remaining huge different is choice. If you want to run an XPages app, you (more or less) just use Domino. For Servlet apps, there are a lot of options. And, importantly, there are two main types: basic servlet containers and full-fledged EE application servers.

The primary normal servlet container you're likely to have heard of is Apache Tomcat. It's very commonly used as an embedded server with Java web apps like Artifactory. Jetty is the other common one to know about, and it serves a similar role, and apparently has found its place as embedded plumbing inside complicated systems.

Those server won't inherently run a Java EE application, however. For example - if you try to deploy the app from the previous entry to Tomcat, it won't load up the JAX-RS services, since the undergirding infrastructure won't be there to pick up on them. You can, though, kind of piece together your own app server on top of Tomcat: if you include a JAX-RS implementation as a Maven dependency, you could make it work. This is a nice ability for if you only one to use one technology or are trying out something bleeding-edge that hasn't made it into a full server yet.

We'll largely be working with full EE servers, though - it's just more convenient to have these things provided by the container rather than having to pick from the buffet of implementations and provide connective glue to make them work together. The ones you're most likely to run into here (unless you fork over tons of cash for a commercial one) are GlassFish (the reference implementation, on its way to Eclipse), its cousin Payara, TomEE (conceptually Tomcat with bundled EE addons), WildFly, and Open Liberty (which I'm partial to).

Choosing

Hypothetically, all of the EE servers are mutually compatible when it comes to the specs, and this plays out well for the most part. If you write a JAX-RS-based application like our example, it doesn't matter too much if you're running on WildFly (which uses RESTEasy for JAX-RS) or Liberty (which uses Apache CXF): neither needs additional configuration and they'll both do the same thing.

As usual, things get fiddly around the edges. For example, file handling in JAX-RS has historically been something of a mess, with each implementation having their own custom extension to the standard. Sometimes, it's more subtle: when working on my blog app, I discovered that Liberty serves up text/html responses from JAX-RS with a header specifying ISO-8859-1 encoding, leading me to write a filter class to override this.

The larger your deployment, the more you'll care about the differences, too. Each server has different mechanisms for management/administration, clustering, and so forth. If you're in a situation where you or your company has already thrown in with one, you may as well stick with that, or pick one as closely related to what you do as possible. That's one of the reasons I've been using Liberty so much: since it has a common ancestry with the XPages runtime, some bits are familiar. Otherwise, unless you already have a business relationship with one of the commercial vendors, you can just pick whichever one suits your fancy.

Next Steps

I think that the next post will dive back into some actual code, specifically the pretty-important topic of actually serving up web pages.

XPages to Java EE, Part 3: Hello, World

  • Jan 21, 2019

I expect that I'll have some more theory and explanation to get to in future posts, but I think it will be useful to run through a quick example project. Unlike with my XPages/OSGi examples, there won't be anything in this one that you wouldn't find in any old Java EE tutorial - indeed, I'll be piggybacking on some existing ones to speed things along.

Eclipse Setup

Strictly speaking, none of this tutorial requires Eclipse, so you can feel free to use IntelliJ (or the command line, or whatever), but most of us probably have Eclipse around at this point. The main thing you'll need is to ensure that you have the "Java EE"/"Enterprise Java" variant of Eclipse from their downloads page. That's been the go-to one for XPages library development all along, so you may already have it.

Additionally, you'll need at least Java 8 installed and configured. I think that recent Eclipse versions require that, so you should be fine there too.

Creating the Project

To create the project, go to File -> New -> Other..., and then chose "Maven Project":

Click Next >, and leave the following page at its defaults:

The next page asks about the "archetype" to use. In Maven terminology, an archetype is a template project that comes pre-populated with configuration information for a given project type. In our case, we'll add an archetype from outside the list - specifically, a quickstart project from Adam Bien, who is a great resource for Java EE knowledge.

To do this, click on Add Archetype... and fill in the Group Id "com.airhacks", the Artifact Id "javaee8-essentials-archetype", and Version "0.0.1":

Leave "Repository URL" blank, click OK, and then select the newly-added archetype on the original page:

After that, click Next >, which will bring you to a screen to provide Maven artifact details. Set the Group Name to "com.example" and the Artifact ID to "javaeetutorial". Leave the other fields as they are.

After that, click Finish. If all goes well, Eclipse will create the project and gussy it up with its Java EE support, resulting in a project that looks like this:

Adding a JAX-RS Resource

At this point, you have a Java EE project primed for use, but it doesn't really do anything yet. For a modern Java app, your most likely starting point is going to be JAX-RS, so we'll create an example service there. If you've created a Wink service for Domino before, this will be familiar, but slightly easier now that so much configuration is implied.

To start, expand the "Java Resources" node of the project, right-click the "src/main/resources" entry, and choose New -> Class:

Set the package to "com.example" and the class name to "HelloWorldResource". Leave everything else as-is and hit Finish:

Set the contents of the class to the following:

package com.example;

import javax.json.Json;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("helloworld")
public class HelloWorldResource {
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public String hello(@QueryParam("name") String name) {
		return Json.createObjectBuilder()
			.add("message", "Hello, " + name) //$NON-NLS-1$ //$NON-NLS-2$
			.build()
			.toString();
	}
}

This is pretty similar to the previous series's REST resource, but it removes the Domino references and switches from IBM Commons's JSON implementation to the relatively-new JSON-P standard. JSON-P and its companion spec JSON-B aim to bring some consistency to the world of JSON handling in Java, though their usage is far behind other implementations like Gson or Jackson. They're part of the Java EE spec, though, so they come "for free" with our project, and they're pretty good.

Running the App

At this point, we have enough to build a .war file out of the app and deploy it to a suitable app server, and that can be done a number of ways. The route we'll take for now is the Maven-focused route: providing enough configuration in the project's pom.xml to run on a chosen app server, in this case TomEE, the Java EE variant of Tomcat.

To accomplish this, open the project's pom.xml file and set its contents to:

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.example</groupId>
	<artifactId>javaeetutorial</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<dependencies>
		<dependency>
			<groupId>javax</groupId>
			<artifactId>javaee-api</artifactId>
			<version>8.0</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	<build>
		<finalName>javaeetutorial</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.tomee.maven</groupId>
				<artifactId>tomee-maven-plugin</artifactId>
				<version>8.0.0-M1</version>
				<configuration>
					<tomeeVersion>8.0.0-M1</tomeeVersion>
					<tomeeClassifier>plus</tomeeClassifier>
					<tomeeHttpPort>9091</tomeeHttpPort>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<properties>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
		<failOnMissingWebXml>false</failOnMissingWebXml>
	</properties>
</project>

Like before, there's a bit of "just paste in the XML" to Maven, but fortunately it's a much smaller bite than when we were dealing with OSGi. The addition here is to add the tomee-maven-plugin pointing to the current milestone release as of this writing.

Once you've saved this file, right-click the project in Eclipse and choose Run As -> Maven Build... (with the ellipsis):

In the resulting dialog, enter "install tomee:run" in the "Goals" field:

Click Run and let the build proceed. It will churn a bit, first compiling the project and then downloading the necessary components to run the server.

If all goes well, you should see a lot of chatter in Eclipse's output finishing (most likely) with a line about "Server startup". You should then be able to visit http://localhost:9091/javaeetutorial/resources/helloworld?name=World and see JSON output from the service:

Next Steps

At this point, you should have a working Java EE application using possibly the most important part of the stack. From here, we'll enter into the worlds of data storage, managed beans, and front-end UI toolkits.

XPages to Java EE, Part 2: Terminology

  • Jan 18, 2019

Much like with my earlier series, I think it'll be useful to take a minute to go over some of the terms that we'll need to know for dealing with Java EE, beyond just the many names of the platform. Additionally, I think it'll be useful to go over some of the things we specifically need to not know when it comes to non-OSGi development.

What To Leave Behind

Looking at my earlier vocabulary list, everything other than "JAR" and (unsurprisingly) "Java EE" can be eschewed from our brains for now. Bundles, plugins, update sites, "Require-Bundle", "Import-Package", all that stuff - forget it. That's all specific to OSGi and, while you can write Java EE apps in an OSGi environment (like XPages), it's very uncommon.

Unfortunately, even outside of XPages specifically, Eclipse conflates OSGi and non-OSGi development a lot, doing things like offering to modify the project classpath instead of OSGi metadata in plug-in projects and vice-versa in non-plug-in ones. It took me a while when getting up to speed on Java to figure out what was "normal Java", what was OSGi, and what was just an Eclipse-ism.

Fortunately, that separation will be made easier by our Maven focus. If it doesn't exist in the Maven project, it doesn't exist at all, regardless of what Eclipse says.

What To Keep

One of the promises of XPages at the start was that it would be a bridge to "normal" Java technologies, and, though imperfectly, it did achieve this goal. A lot of the concepts and technologies we encountered in XPages are either the same in stock Java EE or are historically related.

For one, the normal Java runtime is the same - all the classes starting with java.*, like java.io.List and whatnot. Those are part of "Java SE", and they'll come with you wherever you go in Java.

Additionally, XPages uses Servlet as its basis like most other Java web tools. In XPages, you can access things like the HttpServletRequest and HttpServletResponse by way of #{facesContext.externalContext.request} et al, and those objects are the same in a normal web app.

The "WEB-INF" folder that shows up inside an XPage'd NSF is also an EE-ism, and is the holding pen for "app stuff": configuration, dependency libraries, classes, and other bits all go in here. In an NSF, this is tucked away under "WebContent" (which I think is a semi-standard structural location for resources in uncompiled projects), but the idea is the same. "WEB-INF/lib" in there holds third-party jars, while the hidden-in-Package-Explorer "WEB-INF/classes" holds the compiled classes for the application.

Thanks to the Extension Library, we've also had a surprisingly-smooth introduction to one of the most-important current Java EE technologies: JAX-RS. The ExtLib packaged up Apache Wink, a now-defunct implementation of the standard, and made it pretty easy to build on with OSGi plugins. Even though the version of JAX-RS Wink implemented is a little old, the core concepts are the same, and so, if you ever walked down that path, that knowledge will serve you directly.

What To Learn

There's potentially a whole ton to learn, but we'll start with a couple core concepts.

  • WEB-INF/web.xml- The web.xml file is the traditional core configuration point for a Java web app. You can specify configuration parameters, Servlet mappings, filters, and other bits here - though, over the years, annotation-based improvements have made it so that this file is now strictly optional during development. XPages doesn't have one of these in the NSF (it has kind of a pseudo implied one in the aether), but xsp.properties and faces-config.xml are conceptually related.
  • Web Application - I've been bandying around this term, and it's essentially the name of the finished product you put on a server. In XPages, an NSF is the main Web Application analogue: it's a contained blob of code that has its own internal configuration and identity.
  • Servlet Container, Web Container, or Application Server - These are varying terms for the software that loads and runs the web applications. In our case, that's Domino and its HTTP stack; in others, that will be Tomcat, WebSphere, GlassFish, or the like. Domino is technically a servlet container in two areas: the ancient "Java Servlets" support that haunts our server configuration documents and help docs to this day, and the hacked-apart subset of WebSphere that runs the XPages side of things.
  • Specs and Implementations - For cultural and historical reasons, the Java EE platform itself is a set of specifications, and each of those has at least one implementation, and one of THOSE is dubbed the "reference implementation" (usually developed with the spec and often coming from Oracle). So JAX-RS is a spec, while Jersey, Wink, CXF, and RESTEasy are implementations. For the most part, you don't need to care about the implementation, but you might if you want an extra feature that the spec doesn't provide or (as we'll talk about eventually) are deploying to a "bare bones" servlet container like Tomcat. When deploying to a Java EE server, you normally just write to the spec and the server will include some implementation to back it up.
  • Persistence - "Persistence" in this context basically means "databases". The most common database connection scheme for Java EE is JPA (Java Persistence API, you see) using JDBC to connect to a relational database. For NoSQL databases, the incubating project JNoSQL aims to behave similarly, though it doesn't have critical mass yet. With Domino, we never really had a layer like this - we either dealt with the lotus.domino API or xp:dominoDocument data sources, and those are much "closer to the metal", offering no object mapping or event hooks.
  • MicroProfile - Eclipse MicroProfile is a project started a couple years ago to take several of the most useful Java EE specifications, add a few new tricks, and create a small and speedy target without the huge code and political overhead of Java EE. Since it was started, Java EE went to Eclipse as well, and now Venn diagram of the two is getting closer together: MicroProfile picked up another EE spec or two and EE got its act together and shed a lot of the obligatory baggage. It can be thought of now as an "opinionated" subset of EE that's purpose-focused on microservices.
  • CDI - I've talked a bit before about CDI, and it deserves another mention here both because of its importance to EE development and because of how weird and "magic" its behavior is. At its core, CDI is "managed beans with super powers". While managed beans began their life in JSF (I believe), they're so useful as a concept that they were brought down the stack to become one of the underpinning technologies. Where things get weird is that, beyond just saying "I have a session-scoped bean named 'foo' with type SomeClass", CDI covers auto-injecting instances of classes into other objects and, in some cases, auto-creating implementations of interfaces via proxy objects. It can get really strange really fast, but the basics will hopefully be clear when we get to examples.

Next Steps

I figure that two posts of theory are enough for now, so, in the next post, I'll go through some steps to cover the creation of a new Java EE 8 application.

XPages to Java EE, Part 1: Overview

  • Jan 17, 2019

I've definitely come around to the idea that the future for Java with Domino involves Java/Jakarta EE. HCL apparently feels the same way, though what that "J2EE" bit on their slide means remains unspecified. Regardless, I think that it's important for the XPages community to at least dip our toes into JEE proper, and I plan to share some of my experiences with doing so.

I think the best starting point here will be a bit of history and context. As XPages developers, we were dropped into a weird alternate version of this world, and kind of backed into a lot of its concepts, so it'll be useful to get a feel for where this stuff came from.

Before I get into it, I should point out the significant caveat that I am not a full expert in all of this. I wasn't paying attention to J2EE when it came into being, and there are still large swaths of it that I haven't had to bother with. In particular, I have only a loose grasp of the various turmoils of pricing and vendors over the years, but fortunately those parts aren't too important for getting started now.

Naming History

In 1999, Sun released the first version of JEE, dubbed "Java 2 Platform, Enterprise Edition 1.2". Historically, the versioning of Java has been pretty... well, stupid. Because Sun wanted to make the 1.2 release of Java sound like a big deal, they called it "Java 2" in branding but didn't actually bump the internal version number to match. Java EE matched this, starting out as "J2EE". This type of branding - "J2EE 1.4" - lasted until the fourth release, "Java EE 5" (yeah, I know). The platform is still habitually called "J2EE", but it means the same thing as "JEE".

In 2017, after a couple years of neglect, Oracle decided that they didn't want to be bothered shepherding the platform anymore, and they did the honorable thing and open-sourced it to Eclipse. Since Oracle still maintains the "Java" name, that led to a bit of a scramble to come up with a new name for the platform. The initial name was "EE4J", and that remains the official name of the Eclipse project overseeing the whole thing, as well as the name of the specific reference implementation. After polling the community, though, the name "Jakarta EE" was chosen for the new version of the Java EE standard.

In short, though there are technical differences at each point, the gist of it is that "J2EE", "Java EE", "JEE", "EE4J", and "Jakarta EE" all kind of refer to the same thing.

The Core Meaning

The Java EE platform covers a lot of things and isn't strictly tied to web applications alone, but it effectively means "Java web stuff". For writing the types of web applications we're likely to run across, there's a whole swath of Java EE technology that we'll ignore - stuff to do with the giant, bloated-yet-fragile apps that we learned to associate with WebSphere in the bad old days.

Pricing History

As an "enterprise" offering, Java EE used to involve writing giant checks. You'd pick your vendor, send them a dump truck of money, and they'd give you an application development environment and a team of consultants to install it.

Over the years, things got a lot better. The licensing on the specifications was/became such that open-source versions of core components gradually became available, and then eventually even the big-ticket application servers went open source in various forms and to various extents.

While there used to be a huge hurdle to getting started, we're living in a comparative golden age where you can get top-tier stuff for production use easily and for free.

XPages's Relationship

XPages is effectively a fork of a specific set of Java EE technologies. The most important of this is JavaServer Faces, but it has a couple others in there: Servlet, JavaMail, JAX-RS (in the ExtLib), a janky version of JSP, and probably a grab bag of smaller technologies.

So XPages is Java EE and Domino is a Java EE server in that sense, but its historical division and the presence of OSGi make it so that you can't necessarily just jump in with current JEE development and deploy it to Domino. Some bits are easier than others (like JAX-RS), but everything has an asterisk.

Moreover, the specifics of XPages force us to "un-learn" some things that we learned while getting deeper into Java on Domino. OSGi is the big one - though it still exists, particularly in Eclipse, it has limited adoption for web apps. Additionally, the "develop live in the NSF" methodology, direct pairing of app + storage, and total lack of persistence framework for Domino mean that a lot of our ingrained habits run counter to what we'll learn in the future.

The Plan

Currently, I have only a loose plan in mind for this series. I expect I'll have another post or two of "conceptual" stuff before going into showing some actual code. For the most part, I expect the code will start where the Java Thing Series left off - not with picking up that code specifically, but with the starting point of Maven and Eclipse.

SNTT(uesday): Stepping Up My Tycho Game

  • Jan 15, 2019

I'm always on the lookout for ways to improve my projects' build process to get more-convenient results, cut down on IDE/compiler complaints, or to generally reduce the amount of manual work.

In the last couple weeks, I've figured out two changes to make that clean up my setup nicely: better source bundles and easier update sites.

Source Bundles

In OSGi parlance, a "source bundle" is a companion bundle/plugin for a normal bundle that contains the source code associated with it - for example, org.openntf.domino is paired with org.openntf.domino.source. With a bundle like this present, an IDE (Designer included) can pick up on the presence of the source code and use it for Javadoc and showing the original source of a class. It's extraordinarily convenient, rather than having to reference the source online or in another project (or not at all).

For a while, I've configured my Tycho projects to automatically generate these source bundles during build, and then I have ".source" features that reference them, which are then included in the final update site. This works very well, but it leaves the nagging problem that Eclipse complains about not being able to find the auto-vivified source bundles, and it also requires either putting the source bundles in the main features (which is a bit inefficient in e.g. a server deployment) or maintaining a separate ".source" feature.

It turns out that the answer has been in Tycho all along: instead of just generating source bundles, you can tell it to generate entire source features on the fly. You can do this by using the aptly-named tycho-source-feature-plugin:

<plugin>
	<groupId>org.eclipse.tycho.extras</groupId>
	<artifactId>tycho-source-feature-plugin</artifactId>
	<version>${tycho-version}</version>
	<executions>
		<execution>
			<id>source-feature</id>
			<phase>package</phase>
			<goals>
				<goal>source-feature</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<includeBinaryFeature>false</includeBinaryFeature>
	</configuration>
</plugin>

With this, the build will auto-create the features as it goes, including pulling in the source of any referenced third-party bundles, and then you can include them in the final update site. For example, if the feature you're building is com.example.foo.feature, you can include com.example.foo.feature.source in your output.

Eclipse Repositories

Historically, the way Domino-targeted update sites are built is that they're referred to as the project type eclipse-update-site, which takes a site.xml and turns it into the final update site. This works well enough, but it has a couple problems. For one, it's deprecated and ostensibly slated for removal down the line, and it's best to not rely on anything like that. But otherwise, even when it works, it's fiddly: if you want to, for example, bring in a third-party feature, you have to explicitly specify the version of the feature you're bringing in, rather than letting the build environment pick up on what it is. This can turn into a drag over time, and it's always felt like unnecessary maintenance.

The immediate replacement for eclipse-update-site is eclipse-repository, which is very similar (you can "convert" by just changing the project type and renaming site.xml to category.xml) and solves the second problem. In a category.xml file, you can specify just the feature ID, leaving the version out or specified as 0.0.0, and it'll figure it out during the build.

However, this has a minor down side: though Designer can deal with these repositories without issue, the NSF Update Site template doesn't know about the generated artifacts.jar and content.jar files. You can use "Import Features", but that loses the feature categories, which are very useful when maintaining a large update site.

Fortunately, the site.xml format is extremely basic, so I created a Maven plugin a while ago to auto-generate one of these files. I improved it yesterday to pick up on the categories specified in the original category.xml file. This let me tweak the eclipse-repository project to shim in this generation before the final packaging:

<build>
	<plugins>
		<plugin>
			<groupId>org.darwino</groupId>
			<artifactId>p2sitexml-maven-plugin</artifactId>
			<version>1.1.0</version>
			<executions>
				<execution>
					<id>generate-sitexml</id>
					<goals>
						<goal>generate-site-xml</goal>
					</goals>
					<phase>package</phase>
				</execution>
			</executions>
		</plugin>
		<plugin>
			<groupId>org.eclipse.tycho</groupId>
			<artifactId>tycho-p2-repository-plugin</artifactId>
			<executions>
				<execution>
					<id>archive-repository</id>
					<goals>
						<goal>archive-repository</goal>
					</goals>
					<phase>package</phase>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

Now it's sort of a "best of both worlds" deal: I can use the non-deprecated form of the repository and its improved features, while still using the stock NSF Update Site.

This Maven plugin is in OpenNTF's Maven repository, so you can add it in by adding the repo to your root project's pom:

<pluginRepositories>
	<pluginRepository>
		<id>artifactory.openntf.org</id>
		<name>artifactory.openntf.org</name>
		<url>https://artifactory.openntf.org/openntf</url>
	</pluginRepository>
</pluginRepositories>

 

Letting Madness Take Hold: XPages Outside Domino

  • Jan 7, 2019

(Opening caveat: unlike some of my other recent dalliances, I don't plan to actually do anything with this one, and it's more of a meandering exploration of the XPages platform)

Since I've been on a real Open Liberty kick lately, over the weekend I decided to go another step further and test something I'd been wondering for a while: whether it'd be possible to run the current form XPages outside of the Domino HTTP stack.

I say "the current form" because XPages's history is long and winding, and led a fruitful life for a long time before being glommed onto Domino at all. If you poke around the core, you can see it bears all the scars of its life: references to WebSphere Portal abound, half of the plugins that make up the runtime are just thin OSGi wrappers around plain old Jars, and all of the "Domino" bits are clearly labeled as "adapters".

Still, it's been over a decade since the stack was intended to run anywhere outside Domino, and that's a lot of time for ingrained assumptions about nHTTP specifically to creep in. Still, I was curious if it was possible to load it up outside of Domino and without OSGi.

Short Answer

Yep!

Long Answer

There are a couple things that contribute to making this setup practical, and they each bear some expansion.

Platforms and Execution Contexts

At a couple levels, the runtime breaks things up into generic concepts of "Platforms" and "ExecutionContexts" to handle some specifics about context directories, class loaders, and other bits. For example, if you get a type hierarchy on com.ibm.commons.Platform in Designer, you'll get a pretty immediate idea of what's going on:

OSGi/Services Bridge

Anyone who has written an XPages Library plugin is familiar with the concept of an OSGi extension: you declare your extension (for our purposes, and usefully, com.ibm.commons.Extension) in plugin.xml and then the environment picks up on it by the code looking for such extensions. The core Java runtime has a similar mechanism - ServiceLoader - that looks for files with the name of the extension type in the META-INF/services directory in your classpath. The result of both is the same: individual Jars/plugins can declare services and some other part of the app can pick up on them without knowing the specifics.

XPages uses IBM Commons's generic "Extension" type to paper over the differences between these, and the runtime will look for both or either depending on where it's working. And here's another part that conveniently still retains the vestiges of its youth: if you look inside the com.ibm.xsp.core plugin (since it's just a ZIP file), you can see these extensions declared both in the top-level plugin.xml and as individual files inside the embedded Jar:

So, if you load in these inner Jars as normal Maven dependencies in a .war file, the services will still tie together in much the same way, at least for the core runtime. Things get less convenient the newer the code is, though: the Extension Library, for example, primarily uses plugin.xml for its services, and so either an adapter runtime would have to look for this or you'd have to re-declare them in the "normal" way.

Light OSGi Use

Speaking of OSGi, that's one of the big potential stumbling blocks. XPages nowadays expects to run inside an Equinox container, and so a lot of code (say, the Dojo plugins) make assumptions about the loading of Activator classes and other things. These need some patching. Fortunately, the actual use of OSGi in most of these cases is extremely light: mostly, it's about instantiating these activators and then getting bundle class loaders. For basic needs, these can just be shimmed in: find the (blessedly public) static instance property in the applicable classes and put in small BundleContext+Bundle adapters that just return the context class loader. I'm sure there are bits that run deeper than that, and long-term it'd probably be more practical to just fire up Equinox, but this works for now.

FacesServlet

The core work of rendering an XPage runs through the class FacesServlet and more specifically DesignerFacesServlet (as a side note, I've gathered that seeing "Designer" in these classes refers most likely to "Lotus Component Designer", since those parts of the stack enter in before the Domino dependencies). In a modern JEE context, this'll take a little bit of wrapping, since it implements Servlet but doesn't extend HttpServlet, but not too much. For the most part, once you have your platform set up above, you can make a standard @WebServlet-annoted class and delegate the HttpServletRequest and HttpServletResponse objects to one of these, and it'll pick up on any compiled xsp.PageName classes in your .war:

@Override
public void init(ServletConfig config) throws ServletException {
  this.delegate = new DesignerFacesServlet();
  delegate.init(config);
}

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {	
    delegate.service(new LibertyServletRequestWrapper(req), resp);
}

 

DesignerGlobalResourceServlet

Alongside the core Faces servlet, the DesignerGlobalResourceServlet does the work of, well, serving up global resources. This one's simpler than the Faces servlet, since it is indeed a fully-fledged HttpServlet. You could just declare this in your web.xml, but I like extending these classes in case I want to fiddle with them later:

@WebServlet(urlPatterns="/xsp/.ibmxspres/*")
public class LibertyGlobalFacesResourceServlet extends DesignerGlobalResourceServlet {
	private static final long serialVersionUID = 1L;
}

The NSF Part

Up until now, what I was able to create was a way to run XPages inside a normal web app without any real connection to Domino (other than pulling in the binary plugins). Actually running an existing XPage out of an NSF requires a little more bootstrapping, and unfortunately confines the page a bit.

Specifically, the most expedient route I found to accomplishing this was to fire up an LCDEnvironment object and ferry requests for NSF-hosted apps to this. With the presence of an active Notes runtime (via NotesThread.sinitThread() and bringing in Notes.jar and the NAPI plugin), LCDEnvironment#initialize will do a lot of legwork in assembling its own little world inside your application. It will look for com.ibm.designer.runtime.domino.adapter.HttpService declarations and bring them in, including the vitally-important NSFService.

The nice part of this is that it does a ton of work, handling not just XPages requests, but also in-NSF resource requests. The down side is that the NSFService does its work by heavily wrapping the environment, down to providing a servlet context that declares itself as 2.4 even in a 4.0 runtime. Still, a bit of code in the service method gets it working nicely:

String contextPath = StringUtil.toString(req.getContextPath());
String path = req.getRequestURI().substring(contextPath.length());
RequestContext requestContext = new RequestContext(contextPath, path);
HttpSessionAdapter sessionAdapter = new ServletHttpSessionAdapter(req.getSession());
HttpServletRequestAdapter requestAdapter = new LibertyServletRequestWrapper(req);
HttpServletResponseAdapter responseAdapter = new ServletHttpServletResponseAdapter(resp);
lcdEnvironment.service(requestContext, sessionAdapter, requestAdapter, responseAdapter);

Those adapter/wrapper classes really just delegate the calls, but they're needed because that's what LCDEnvironment expects. I imagine those interfaces exist to create a consistent environment in lots of situations without even tying to the stock HttpServlet* classes. In general, the XPages stack loves adapters.

So, Is This A Good Way To Run XPages?

Nnnnnnnnnope! I mean, not really. Particularly in the first route, where you load up an XPage without any knowledge of the NSF part, you have some intriguing paths to interact with the surrounding Servlet 4.0 environment directly from the page. However, I don't know why you would do this. You could hypothetically create some components or hooks to allow use of, say, Web Sockets, but you'd be better off just using current JSF for that, since the work is already done. The in-NSF XPages runtime adds some extra barriers to that, too... I'm sure it'd be possible to provide a path to it, but, again, you'd be better off using existing tech.

Additionally, this isn't a way to bring XPages "home" to JSF. The JSF API and implementation that XPages uses isn't merely old, but hacked to pieces: if you look at javax.faces.component.UIComponent, you can see it's riddled with "_xsp" methods, indicating a thoroughly-unclean layering. You wouldn't be able to shim in the current JSF without forking it into a distinct project.

Still, it's nice to know it's possible, and it sure was a fun project to tinker with. I do admit that the notion of building an XPages app using MVC 1.0 with XPages as the view technology is a little tantalizing, but it's certainly not worth traveling down that road on the back of a chopped-up hacky rework of the platform. And the only reason it's tantalizing is that I'm still more comfortable with XPages than any of the other front-end stacks, and that doesn't itself make it a good fit. Fun to think about, though.

New Project: Domino Open Liberty Runtime

  • Jan 3, 2019

The end of the year is often a good time to catch up on some side projects, and this past couple weeks saw me back to focusing on what to do about our collective unfortunate situation. I started by expanding the org.openntf.xsp.jakartaee project to include several additional JEE standards, but then my efforts took a bit of a turn.

Specifically, I thought about Sven Hasselbach's series on dropping Domino's HTTP stack while still keeping API access to Domino data, and decided to take a slightly-different approach. For one, instead of the plucky-but-not-feature-rich Jetty, my eye turned to Open Liberty, the open-source variant of WebSphere Liberty, which in turn is the surprisingly-pleasant trimmed-down counterpart to WebSphere. Using Liberty instead of Jetty means getting a top-tier Java EE runtime, supporting the full Java EE 8 and MicroProfile 2.1 specs, developed by a team chomping at the bit to support all the latest goodies.

Additionally, I decided to try launching Liberty from a Domino plugin, and this bore fruit immediately: with this association, the Liberty runtime is able to fire up sessions and access databases as the Domino server without causing the panic halt that Sven ran into.

So, in short, what this project does is add a fully-capable Java EE server with all the fixings - the latest JEE spec, HTTP/2, Servlet 4, WebSockets, and so forth - running with native access to Domino data alongside a normal server, and with the ability to manage configuration and app deployment via NSFs. Essentially, it's like a second HTTP stack.

Why?

I made some good progress in bringing individual JEE technologies to XPages, but I was still constrained by the core capabilities of the XPages runtime, not the least of which was its use of Servlet 2.4, a standard that went obsolete in two-thousand-freaking-five. Every step of the project involves fighting against the whole underlying stack, just to get some niceties that come for free if you start with a modern web container.

Additionally, while Domino has the ability to run Java web applications, this support is similarly limited, providing very few of the standards that make up Java EE and even apparently lacking a JSP compiler set up on the server. It's also, by virtue of necessarily wrapping the app in an OSGi bundle, much fiddlier to develop than a normal WAR file.

And, in a general sense, I'm tired of waiting for this stack to get better. Maybe HCL has grand plans for Java development on Domino in the future - they haven't said. I still doubt it, in part because of the huge amount of work it would entail and in part because I'm not sure that improving XPages would even be strategically wise for them. And say they did improve XPages in a lot of ways people have been clamoring for - WebSockets and whatnot. Would they cover all of the desired features? What about newly-emerging technologies from outside? Their Node.JS strategy makes me think they've thought better of being the vendor of a full-stack web technology.

This route, though, provides a route to making web apps with current standards regardless of what HCL does with XPages. This way, you can work with the entire Java web community at your back, rather than cloistered off with unknown technology. If you want to make an app with Spring, you can, following all of their examples. If you'd rather use PrimeFaces, or just JAX-RS, or JSP, you can do so just as easily. And if your chosen technologies go out of favor, you'll be in the same boat as countless others, and the new preferred choices will be open to you.

Finally, there's just the fact that Java EE 8 is really, really good. The platform made tremendous strides since the bad old days, and developing an app with it is a revitalizing experience.

How?

To set this up, I deliberately chose a very low-integration path: the task in Domino unzips a normal Open Liberty distribution and then runs it using Domino's JVM, just using the default bin/server script. No embedding, no shared runtime. This way, it doesn't have to fight against any constraints that Domino's environment imposes (such as the fact that both Domino and Liberty want to run an OSGi environment), and it doesn't lead to a situation where a crash in Liberty would bring down Domino's HTTP.

The rest kind of comes along for the ride. Since it's running with the Domino JVM, it already has the trappings needed to use Notes.jar, so it's really just a matter of using the classes and making sure you run inside a NotesThread or otherwise initialize and terminate your thread.

Future

Assuming I keep with this project (and I think I have some for-work uses for it, which dramatically increases its odds), I have some ideas for future improvements.

I've added a basic HTTP reverse proxy servlet, and I plan to make it more integrated. The idea there is to allow Liberty to be the primary HTTP entrypoint for Domino, with anything not handled by a web app it's hosting to pass through transparently to Domino.

In time, I aim to add some more integration, such as CrossWorlds and general utilities. I've started by adding in a basic user registry, allowing JEE-standard apps to authenticate against Domino without extra configuration (though it doesn't currently do groups). That could be expanded a good deal - Liberty could read SSO tokens using the C API (or share LTPA as WebSphere normally does), and it'd be nice to have a reasonable method for sharing non-SSO DomAuthSessId cookies.

The Project

I set up on the project on GitHub: https://github.com/OpenNTF/openliberty-domino . I think there's some definite promise with this, especially once there are a couple example apps that could show off the possibilities.