XPages to Java EE, Part 4: Application Servers

Wed Jan 23 12:03:58 EST 2019

Tags: javaee
  1. XPages to Java EE, Part 1: Overview
  2. XPages to Java EE, Part 2: Terminology
  3. XPages to Java EE, Part 3: Hello, World
  4. XPages to Java EE, Part 4: Application Servers
  5. XPages to Java EE, Part 5: Web Pages
  6. XPages to Java EE, Part 6: Dependencies
  7. XPages to Java EE, Part 7: MVC
  8. XPages to Java EE, Part 8: IDE Server Integration
  9. XPages to Java EE, Part 9: IDE Features Grab Bag
  10. XPages to Java EE, Part 10: Data Storage
  11. XPages to Java EE, Part 11: Mixing MVC and an API
  12. XPages to Java EE, Part 12: Container Authentication
  13. XPages to Java EE, Part 13: Why Do This, Anyway?

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

Mon Jan 21 14:31:00 EST 2019

Tags: javaee
  1. XPages to Java EE, Part 1: Overview
  2. XPages to Java EE, Part 2: Terminology
  3. XPages to Java EE, Part 3: Hello, World
  4. XPages to Java EE, Part 4: Application Servers
  5. XPages to Java EE, Part 5: Web Pages
  6. XPages to Java EE, Part 6: Dependencies
  7. XPages to Java EE, Part 7: MVC
  8. XPages to Java EE, Part 8: IDE Server Integration
  9. XPages to Java EE, Part 9: IDE Features Grab Bag
  10. XPages to Java EE, Part 10: Data Storage
  11. XPages to Java EE, Part 11: Mixing MVC and an API
  12. XPages to Java EE, Part 12: Container Authentication
  13. XPages to Java EE, Part 13: Why Do This, Anyway?

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

Fri Jan 18 13:09:06 EST 2019

Tags: javaee
  1. XPages to Java EE, Part 1: Overview
  2. XPages to Java EE, Part 2: Terminology
  3. XPages to Java EE, Part 3: Hello, World
  4. XPages to Java EE, Part 4: Application Servers
  5. XPages to Java EE, Part 5: Web Pages
  6. XPages to Java EE, Part 6: Dependencies
  7. XPages to Java EE, Part 7: MVC
  8. XPages to Java EE, Part 8: IDE Server Integration
  9. XPages to Java EE, Part 9: IDE Features Grab Bag
  10. XPages to Java EE, Part 10: Data Storage
  11. XPages to Java EE, Part 11: Mixing MVC and an API
  12. XPages to Java EE, Part 12: Container Authentication
  13. XPages to Java EE, Part 13: Why Do This, Anyway?

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

Thu Jan 17 18:54:59 EST 2019

Tags: javaee
  1. XPages to Java EE, Part 1: Overview
  2. XPages to Java EE, Part 2: Terminology
  3. XPages to Java EE, Part 3: Hello, World
  4. XPages to Java EE, Part 4: Application Servers
  5. XPages to Java EE, Part 5: Web Pages
  6. XPages to Java EE, Part 6: Dependencies
  7. XPages to Java EE, Part 7: MVC
  8. XPages to Java EE, Part 8: IDE Server Integration
  9. XPages to Java EE, Part 9: IDE Features Grab Bag
  10. XPages to Java EE, Part 10: Data Storage
  11. XPages to Java EE, Part 11: Mixing MVC and an API
  12. XPages to Java EE, Part 12: Container Authentication
  13. XPages to Java EE, Part 13: Why Do This, Anyway?

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

Tue Jan 15 11:21:45 EST 2019

Tags: sntt tycho

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

Mon Jan 07 10:59:00 EST 2019

Tags: xpages
  1. Letting Madness Take Hold: XPages Outside Domino
  2. XPages on Android
  3. Concept Proven: A Complex Production XPages App Running Outside Domino

(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

Thu Jan 03 17:23:50 EST 2019

Tags: liberty

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.

Learning to Appreciate IntelliJ

Thu Nov 22 11:24:18 EST 2018

Tags: intellij

I'm a big fan of Eclipse, both the IDE and the foundation - I like how organized they are, I like that they're stewarding Jakarta EE, I'm ostensibly a committer, and I even have an Eclipse T-shirt. I'm all in!

However, I have to admit that the IDE has been grating on me for a lot of my work lately. The two big ways are the ever-present troubles when working with OSGi projects and its surprising UI slowness when working with a lot of projects in the workspace. Though it's sitting on top of an eight-core Xeon, it just drags - expand/collapse animation is slow, the editor freezes up frequently when trying to autocomplete, and it's just a dog. I had high hopes that Photon's push for speed would alleviate this, but it's still a drag. I think it's probably faster on Windows, but that's just not worth contemplating.

Moreover, my work with Darwino involves Android apps, and Android development in Eclipse just completely lost steam after Google switched to IntelliJ. The Andmore project aimed to keep it alive, but you can see how far that went just by looking at the release list. It can still kind of work, but it's very much swimming against the current.

So I've been on the lookout for alternate IDEs for some or all of my work. Visual Studio Code has been a strong contender. I've already switched to it for most JavaScript work and it has decent support for Java projects by way of the Java Language Server. However, despite that project being run by Eclipse, it doesn't support Tycho projects, and so I can't use it for full OSGi development. Moreover, though it's very capable, Java support clearly isn't its main focus, and so it won't cover all the same bases as a "proper" Java IDE.

But looming in the corner the whole time has been IntelliJ IDEA. I'd used it here and there for Android apps, and it was okay, but it always rubbed me the wrong way. Part of that is just muscle memory from Eclipse - any different IDE is going to be inherently annoying in some way just because it's different. Some of it was also runoff resentment from working with Android, so I could discount that too. It doesn't help that the UI is written in Swing, and so, even with its Mac-ish coat of paint, it still feels like running some kind of weird Linux app. Eclipse isn't exactly fully Mac-like either, but SWT carries it much further along.

But still, I figured I should give it a real shot. Lots of people swear by it, especially as converts from Eclipse, so it has to do something right. As it turns out, it does quite a bit right.

Speed

So far, I've found it to be significantly snappier than Eclipse for the kind of work I'm doing, and without all the UI blocking that's been plaguing the latter for me for a while. Autocomplete happens quickly and consistently and doesn't freeze the UI, project import processing happens quietly on background threads, and everything just feels smooth.

Java Intelligence

IntelliJ's Java support carries quite a bit of cleverness, and JetBrains made great selections for what to enable by default. It's particularly good at what Eclipse refers to as "code mining", where it will inspect your code and add little visual annotations to make what you're doing more clear. For example, I love what it does with "stream-style" chained code:

IntelliJ "stream" code intermediate classes

It has all sorts of little niceties like this, and does pleasant things like compressing pre-lambda functional-interface calls to look like lambdas even in Java 6 projects. And another favorite: pseudo named parameters, automatically showing when it's most useful for clarity:

Pseudo named parameters

It's also pretty good at recognizing legal-but-inadvisable idioms and offering in-place conversions. For example, if you write this:

String bundles = osgiBundleList.stream().collect(Collectors.joining(","));

...it will have a quick action to convert it to this instead:

String bundles = String.join(",", osgiBundleList);

This sort of thing isn't unique to IntelliJ (Eclipse has some of this and there's no shortage of code-linting tools), but it does a particularly good job integrating it in a useful and non-obtrusive way.

OSGi

Though Eclipse is something of a flagship user of OSGi and so much of the IDE is geared around plug-in development, it sure does make it a real PITA to use sometimes. In particular, the single active Target Platform per workspace, configured manually in the preferences, is a huge hurdle when dealing with multiple diverging OSGi projects.

IntelliJ handles this much better for my needs. Primarily, it does this by letting its OSGi plugin (dubbed Osmorc) construct the platform per-project from whatever the project's dependency mechanism is. In the case of Tycho, this means that it will pick up on any p2 repositories specified within the project (such as the ${notes-platform} one commonly used for XPages libraries) and find the dependencies in much the same way that Tycho itself does. This means you don't have to worry about hand-holding the IDE to make it do a job that the build system already knows how to do.

I think that you wouldn't want necessarily want to use this to run and debug full-fledged Eclipse RCP applications, though I imagine you could via Maven goals if nothing else. For my needs, though, it seems like it hits exactly the right level of support.

External Annotations

I became a convert to null analysis a while ago, and I like to stick with it as much as possible. One of the things that makes it a little awkward, though, is that the core JDK classes - String, etc. - don't have any annotations. Most checking tools, Eclipse included, support the concept of "external annotations": a separate definition file that can tell the compiler that, say, String.valueOf(...) will always return a non-null value without having to modify the compiled classes.

Where IntelliJ's pleasantness comes in is that automatically applies a set of external annotations to the JDK, whereas Eclipse is more of a bring-your-own sort of thing. I never bothered figuring out the right way to do it in Eclipse, and so it's great to just have that set up for me without having to think about it.

JavaScript/TypeScript/etc.

I haven't worked too much with JavaScript apps in IntelliJ yet, but I know that WebStorm is highly regarded, and I sprung for the Ultimate edition, so it's sitting there for me anyway. Just a quick glance shows that it's much more comfortable than Eclipse: I have npm-based JS projects wrapped in Maven projects, and it picks up on both aspects just fine. I can open up a JSX file and it properly builds the class hierarchy, finds dependencies, and all that. Eclipse, on the other hand, hasn't seemed to update its JavaScript editor since about 2001, and the third-party plugins are a mess of limited functionality, incompatibility, and extra cost. It would sure be nice if I can use IntelliJ for my JS dev instead of having to hop between it and VS Code (as nice as VS Code is).

The Future: Plugin Development

I'll go into this more in my next post, but my trial-run project to get comfortable with IntelliJ was to port the run-from-workspace aspect of the XPages SDK to IntelliJ, and I did so successfully. It turns out that the plugin mechanism is characteristically clean and straightforward, at least for what I need to do, and I expect I'll be doing similar work for Darwino.

So, as much as possible, I think I'm going to try living in IntelliJ for a while and see how it treats me. So far, so good, in any event.

Java Hiccups

Wed Nov 07 14:01:00 EST 2018

Tags: java
  1. Java Hiccups
  2. Bitwise Operators
  3. Java Grab Bag 2
  4. Java Travelogue: The Care and Feeding of Locales
  5. More Notes on Filesystem and Charset Portability

To take a break from the doom-and-gloom of my last post, I figured it'd be good to dust off a post idea I've had in my drafts for a while: common hiccups that Java developers - particularly those coming from a Domino background - run into. This is sort of a grab bag of non-obvious concepts that are easy to assume incorrectly about, whether because of the way other languages work or the behavior of the lotus.domino API specifically.

So, roughly in order of complexity:

import Is Just For Cleanliness

In many languages, in particular C/C++/Objective-C, the natural equivalent of Java's import statement has a massive effect, physically grafting files into your source. In Java, though, import is really just for developer convenience. At runtime, there's no difference between having written this:

1
2
3
4
5
import java.util.ArrayList;
import java.util.List;

/* snip */
List<String> foo = new ArrayList<>();

...or this:

1
java.util.List<java.lang.String> foo = new java.util.ArrayList<>();

If you import a class but never use it in a file, it won't have any effect on the runtime behavior of the class. It's just used by the compiler to clarify what you mean when you use a base class name without reference.

Incidentally, as seen here, classes within the java.lang package (but not subpackages) are auto-imported, so it's as if each Java file has an invisible import java.lang.* at the top.

Compilation Doesn't Bake In Libraries

This is related, and is also an area where Java differs from some other environments. With C et al, you have the option to statically link referenced external libraries - which is to say, grab their contents at build time and put them into your compiled result such that they may as well be part of your program. Java doesn't do this: every time you reference a class or method, it's really just storing the equivalent of the string name of that class, which is then resolved at runtime.

This is why it's very easy to run into a ClassNotFoundException: you can compile code with some classes present on the class path, but then run it in a system where they're not present. The Java runtime doesn't pre-check whether all the required classes are available when it starts running, so you only find out when it hits that line of code.

Different Java-based environments deal with this in different ways. Standard (non-Domino) web apps deal with this by including dependency jars inside the WEB-INF/lib folder during the packaging phase of building. OSGi, XPages's framework of choice, has a whole dependency mechanism where you can specify bundles or packages with version ranges, in the hope of bringing some order to the chaos, with mixed success.

Primitives Are A Thing

Though the term "primitive" means a built-in data type generally, here I'm specifically talking about things like int and double. For historical and performance reasons, Java has a conceptual and practical distinction between the objects that you deal with most of the time and the primitive types used mostly for number storage. Namely: byte, char, short, int, long, float, double, and boolean. Unlike object references, there is no concept of a "null" value with these that would cause a NullPointerException. Referring to a variable with one of these types will always contain some value if the code compiles, even if it's just the 0/false default for an object property when not otherwise initialized.

Each of these types has a corresponding "boxed" object version, generally with the un-abbreviated name capitalized, such as Byte and Integer.

The distinction used to be harsher than it is today, thanks to autoboxing. Autoboxing is a compile-time behavior that will automatically convert between the primitive types and their object holders as necessary, allowing this type of code, which would otherwise be illegal:

1
2
Object i = 3;
int j = new Integer(4);

Autoboxing is mildly inefficient, so it's good to know that it exists, but you don't normally need to lose sleep over it.

All Object Variables Are Pointers

In a language like C++, there is a distinction between a variable that "is" an object vs. one that is a pointer to an object somewhere in memory. In Java, however, the former doesn't exist: an object variable is only ever a pointer. This has a couple implications. For one, this code only deals one object:

1
2
3
4
5
SomeClass foo = new SomeClass();
SomeClass bar = foo;
bar.setName("hi");
foo.setName("hello");
bar.getName(); // Will be "hello"

This is also why Java is picky about not referencing object variables until they've been initialized to at least something, so this generates a compile-time error:

1
2
Object foo;
foo.getClass();

Unfortunately, unlike some languages, Java has no language-level support for enforcing the distinction between a null object reference and a non-null one, which is why NullPointerExceptions are so prevalent.

Another implication of this leads into its own hiccup common to LotusScript programmers:

Strictly Speaking, All Method Arguments Are "By Value", But...

All method parameters in Java are "by value" in the LotusScript sense, the fact that all object variables are pointers means that the "value" you're passing to the method for an object parameter is always a reference. Java has no mechanism to pass a reference to a primitive type, nor does it have a mechanism to implicitly duplicate an object when passing it to a method.

Not only is this a bit conceptually confusing at first, but it's also a potential trap for bad programming practices. It's very easy to write a method that performs modifications on objects passed in as parameters, and this is often the right thing to do. However, since the language doesn't have any syntax mechanism for broadcasting this behavior, it's up to you as the programmer to either write the method name in such a way that it's obvious what's going to happen or clearly state it in the documentation if it's something that's going to be used outside the current file.

Casting Objects Doesn't Do Anything

By "casting", I'm referring to something like this:

1
RichTextItem body = (RichTextItem)doc.getFirstItem("SomeItem");

The (RichTextItem) is a cast, and it's yet another area that diverges from some other languages. What casting an object in Java means is that you're going to refer to an object by a different class or interface than the one it's been previously referred to as. It has some runtime implications, but the thing to keep in mind is that it's about choosing the name for something that exists as opposed to changing an object into a different class.

So, for example, the RichTextItem idiom above exists because the Document#getFirstItem method returns an object that's called a Item, but, when the item in the document is rich text, it will actually return a RichTextItem object. RichTextItem is a subclass of Item, and so it's legal to refer to such an object either as RichTextItem, Item, Base (the common interface for all Notes objects), or Object (the common superclass of all objects). In a situation like this, you have to cast the object because you're going to refer to it as a more-specific type of object than the one the method says it returns.

If you do this and the object is not actually of the type you're trying to cast it to (in this case, if it's a plain text item or MIME, most commonly), you'll end up with a ClassCastException, because the cast is enforced at runtime. But, success or fail, the cast will not actually affect the object itself in any way - it will continue on being whatever it was already, regardless of name.

Casting Primitives Does Do Something

For better or for worse, performing a cast on a primitive type does have the possibility of creating a new value. For example:

1
2
int foo = Integer.MAX_VALUE;
short bar = (short)foo;

Because int can hold more data than a short, this case creates a new value based on chopping off the highest-value bits of the internal binary representation of foo. (As a side note, because of the fun way computers deal with numbers, foo is 2147483647, while bar is -1.)

Normally, this behavior doesn't matter too much, since, if you have a method that takes, say, an int and you have a long, you can safely cast it down since it'll likely be a tiny value anyway. It's important to know that it can happen, though, and this behavior is very important when, for example, native C libraries that use unsigned values, which do not exist in Java as such.

Java Has Only A Limited Concept of Immutability

"Immutability" refers to the inability to change the value of an entity once it's created. It's come to the fore as a concept recently because working with immutable objects sidesteps a lot of issues with asynchronous programming. Java, unfortunately, doesn't really have any language-level support for immutable objects in the sense that, for example, Swift does.

Java throws a bit of a curve ball in this area with the final keyword, which means that a variable can't be reassigned after being first initialized. This means that you can't do things like this:

1
2
3
4
5
final int foo = 3;
foo = 4; // compiler error

final SomeClass bar = new SomeClass();
bar = new SomeClass(); // compiler error

This, on the other hand, is entirely legal:

1
2
3
final SomeClass foo = new SomeClass();
foo.setName("hi");
foo.setName("hello");

This is because the only thing blocked from changing here is the value of foo-the-reference, but the object it's referencing can be changed at will.

An object can be made effectively immutable, though, by means of making its outward-facing methods not change any of the internal state. This is used commonly for "value" classes, such as the aforementioned Integer. Though the language doesn't do anything to guarantee that the Integer class doesn't allow mutation, the class is written in such a way that it has no inlet for it.

Because of the value of immutable objects, they're used commonly in the core Java classes and in third-party libraries, particularly newer ones. However, since the language can't tell you if an object is immutable, you have to be on the lookout for whether a given method modifies the existing object in-place or returns a new object reflecting the change. This comes up frequently with Strings, which are immutable in Java. This is something I've seen commonly:

1
2
3
String foo = " hello ";
foo.trim();
System.out.println(foo);

That code will print " hello ", with the leading and trailing spaces (though without the quotes). This is because the String#trim method, like all "changing" methods on String, leaves the original value intact but returns a new String object reflecting the expected value.

This is just something you have to be on the lookout for, especially since this pattern isn't even consistently applied within the core Java classes. The Date class, for example, is infamously bad in a lot of ways, and one of those ways is that it has mutation methods.

Generics In Java Are Weird

A "generic" refers in this case to a class that is declared as being associated with one or more other types that can be defined after the fact. The prototypical example of this is a collection class, like List<String> foo. In this case, the List interface is generic and lets you specify the type of object you expect to find within it, in this case String.

Generics, unfortunately, were added after Java's initial release, and they bear the marks of it. Unlike languages like C++, Java generics are largely syntactic sugar, meant to replace things like:

1
String someString = (String)aListIKnowHasStrings.get(0);

...with this:

1
String someString = aListDeclaredWithStrings.get(0);

However, under the covers, a List only ever really knows it contains Objects, and the second form just transparently shims in a (String) cast at runtime. That's why you can do something like this:

1
((List<Object>)(List<?>)aListDeclaredWithStrings).add(new NotAStringObject());

That line will not only compile, but it will execute without issue at runtime. It's only later, when you try to extract the value to a String variable, that you'll hit a ClassCastException.

Some generic information is retained at runtime, depending on how it's used, but for the most part it's best to think of it as just a syntax nicety. This behavior is endless trouble, but something we have to live with.

Garbage Collection Is Automatic, But Resource Management Isn't Necessarily

This is one of the main things that bites Domino developers as they learn about Java. One of the early things they learn when switching from LotusScript to Java is that now you have to worry about the .recycle() method on your objects, or else you'll have trouble. This leads to two misapprehensions: that Java in general requires "recycling" for every object, and that recycling with Domino objects is about memory in the same way that a Java OutOfMemoryError is.

Unfortunately, the reason that recycle() exists at all requires delving into some nitty-gritty aspects of the Java environment, but I first want to reinforce that Java uses automatic garbage collection at all times to watch for and delete objects that are no longer used. That "no longer used" bit glosses over a bit, but take this as an example:

1
2
3
4
5
6
7
8
9
public void foo() {
  String a = "hello";
  String b = " there";
  return a + b;
}
public void bar() {
  String message = foo();
  System.out.println(message);
}

There are three objects in action here, but, by the time the code reaches the System.out.println line, a and b are no longer used and will be slated for automatic garbage collection. You as a programmer do not need to worry about them.

The lotus.domino objects, though, are trouble. I think it's best to not think of recycle() in terms of "memory" but instead think of the objects as "open resources", in the same way that you might open a network connection or a stream to a file on the filesystem. Unlike object memory, network resources are not necessarily automatically closed by Java - there are some affordances with syntax and the concept of "finalizers", but, in general, the responsibility for closing a resource lies with the programmer.

There are a few grab-bag notes to do with these objects:

  • Different lotus.domino objects refer to different kind of backing resources, which is why problems will sometimes manifest as complaints about memory (when they refer primarily to C-side structures in Domino's native memory, separate from Java) and sometimes as complaints about handles (database and document references, generally)
  • Recycling a "parent" object recycles all of its children, but the relationship is not always clear. Importantly, DateTime objects are children of the ancestor Session, even when you retrieve them from a Document, and so they can linger for a long time
  • Agents and XPages both mitigate and conceal the need for recycling by automatically closing the auto-generated Session(s) at the end of the agent execution or page request. In practice, you only really need to worry about recycling if you're, for example, looping over a large view

I may make another one of these posts in the future, and hopefully this goes a little way to clearing up some common misconceptions.

How Do You Solve a Problem Like XPages?

Fri Nov 02 12:08:08 EDT 2018

Tags: xpages gloom

(Fair warning: this is a meandering one and I'm basically a wet blanket the whole way through)

Last week, HCL held the third of their Twitter-based developer Q&As, with this one focusing on XPages and Designer. The majority of the questions (including, admittedly, all of mine) were along the lines of either "can we get some improvements in the Java/XPages stack?" or "is XPages still supported?". The answer to the latter from HCL, as it would have to be, is that XPages is still alive and "fully supported".

I don't doubt at all that XPages is supported in the sense that it has been for the last couple years: if you as a customer encounter a bug in the platform, support will take your call and will most likely either have a workaround or will get a fix in. This will no doubt happen naturally as time marches on, primarily when a new version of a browser breaks something in the version of Dojo that XPages uses (currently, I believe, a couple notches down the list as 1.9.7). So, that's good, and is better than the worst-case scenario.

It's not great, though. Version 10 had essentially no changes for XPages - that makes sense with its "stanch the bleeding" market goal, but it continues the history of very little progress. Outside of the forced-for-security-reasons bump to Java 8 in 9.0.1FP8 (which is admittedly nice), the last major addition to XPages was the Bluemix tooling via the Extension Library, which, as far as I can tell, only exists because of the way funding politics works inside IBM. Before that, I'd mark it as the promotion of Bootstrap renderers from Bootstrap4XPages to the main ExtLib just shy of four years ago. Before that, it was... I guess adding the ExtLib to the main product in 9.0, which sort of counts. Before that, it was pretty much the introduction of the extension points and ExtLib in the 8.5.2 era. And sessionAsSigner, I suppose.

Not to belabor the point too much further, XPages developers are in an uncomfortable spot. For a decade or so now, XPages was the clear "this is what Domino developers should be doing" choice, especially in the face of many Domino shops wanting to at the very least get rid of the Notes client. However, though it was modern enough when it was introduced, the stack has missed the boat on a lot of evolution, both in simple terms of its Java EE common ancestor improving on its own and in larger terms of changes in the web development world.

Had XPages continued under real active development, it could have gradually improved to fit more comfortably in a world of transpiled JavaScript and CSS pre-processors, strict focus on REST APIs, and reactive and streaming APIs.

But...

But even in that "active development" alternate universe, the path would have been awkward. Though XPages has the capacity to be well-structured, Designer and IBM provided no help on this: no model framework, no internal routing, not even an indication that writing Java code was possible in an XPages app until several versions in. The "MVC" aspects of its JSF components were beaten down to match the expectations of an NSF container and of LotusScript developers. There's very good reason for that - very few Domino shops were likely to send developers to computer-science boot camps to learn about proper Java EE structure, and the only way XPages was going to work at all was if it started out as "forms but with partial refresh".

And, after that first unstructured version, it largely fell prey to the usual problems of enterprise software: IBM isn't in the business of doing things their customers aren't asking for, and the community members asking for, say, a faces-config.xml editor weren't backing those requests up with big licensing checks. I get that, too, I really do. If you spend too much time hypothesizing about and implementing what customers might want, you run the risk of throwing your money down a bottomless hole while your actual customers suffer and leave. So IBM generally swings hard in the other direction, and it's understandable if unfortunate in cases like this, especially when what your customers are strictly asking for is stasis.

So What Now?

Our current situation now is that HCL plans to have a roadmap in Q1 2019, so I suppose we'll wait and see what they say again. I've been mulling over what I think should be the way forward for XPages and its users, and I don't see any clear good solution.

The option that immediately springs to mind is "add more features to it": HTTP/2 and WebSockets, newer renderers, an IDE that encourages good development practices, better way to bring in third-party libraries, cleaner JavaScript, and so forth. But what makes this questionable for me is the sheer amount of work, especially since they'd have to start by digging out of an immense amount of technical debt. And this would be very specialized work indeed - the XPages stack is complicated. I'd wager that just the part of the stack that handles ferrying attachments between the browser and a document is more complex than most entire Domino applications by a good margin. While some of the improvements would be handled via the core Domino server team (part of the HTTP upgrades, namely), HCL would likely have to acquire a team of Java developers and have them learn a giant stack of OSGi, JSF, Domino APIs, a couple decades of legacy decisions before even getting going. Possible? Certainly. It's just kind of a hard sell.

Another possibility would be open-sourcing the stack and either maintaining it as a project themselves, giving it to OpenNTF, or handing it to an organization like Eclipse, which now holds the reins of Java/Jakarta EE generally. I think that open-sourcing it would have immediate benefits to XPages developers regardless of what else they do with it, but I'm skeptical of how much of a life it would have if it was converted to a community-run project. As it stands, I can only think of a handful of people who a) are aware of XPages and b) would be capable of contributing to its core code. That's not a problem if you are employing people to work on it full-time, but I don't think it has a large enough base to exist on a "side project" basis. Attracting new blood would be an uphill battle: even projects like Andmore that have a clear purpose for existing and a contingent of people desperate to keep their workflow can wither on the vine immediately. Outside of Domino developers, XPages would be viewed as "JSF, except old and restricted to a platform you thought died in the 90s".

The other main thing to do with the stack that doesn't involve killing it, I think, would be pushing it to a state that focuses on REST APIs instead of handling the UI itself, which is something that some XPages devs have been doing already, either by switching to plugins serving up JAX-RS services or via in-NSF controls. This is something that IBM kind-of-sort-of said they were aiming for a couple years ago when they put forward SmartNSF as a good option, but the effective demise of the Extension Library cut off its path into the core, at least for now. Overall, I think that this would make sense. The experience of writing REST services inside an NSF (or in an OSGi plugin) is significantly worse than JAX-RS in a normal Java EE or Spring app, but it provides a clear path for existing NSFs and code to continue being used - more or less - without having to set up a second app server. It may not be the preferred solution for Java in Domino, but it would have the advantage of improving the platform without having to worry anymore about how, say, all the core renderers use tables for layout.

For Developers

For XPages developers, my long-proffered advice remains the same: learn things that aren't XPages. Whether that means diving head-first into Java EE or Spring, focusing on client-JS development, learning Node, or any other option, you'll likely be well-served by it.

It's possible that you could continue to do XPages work or go back to the Notes client indefinitely - XPages will get patches if nothing else, and Nomad breathes undeserved life into LotusScript - but there's no guarantee there. There's no guarantee anywhere else, I suppose, but staying too tied to Domino-specific technology keeps you at immediate risk of a from-above directive to switch away.

In short: do not expect a cavalry to ride to your aid.