Posts for query "jnosql", by date descending

XPages to Java EE, Part 11: Mixing MVC and an API

  • Feb 16, 2019

When we set up our MVC controller classes, we put the @Controller annotation at the class level, which tells the environment that the entire class is dedicated to running the UI. However, we don't necessarily always want to do that - JAX-RS is the way to build REST APIs, after all, and so we should also add JSON versions of our Person methods.

Person Model Modification

Before we get to the meat of the code, go back to the Person class and modify it to remove the parameter to the @Id annotation and switch it to a String type:

package model;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.ws.rs.FormParam;

import org.jnosql.artemis.Column;
import org.jnosql.artemis.Entity;
import org.jnosql.artemis.Id;

@Entity
public class Person {
	@Id
	private String id;
	@Column @FormParam("name") @NotBlank
	private String name;
	@Column @FormParam("emailAddress") @NotBlank @Email
	private String emailAddress;
	
	public String getId() { return id; }
	public void setId(String id) { this.id = id; }
	public String getName() { return name; }
	public void setName(String name) { this.name = name; }
	public String getEmailAddress() { return emailAddress; }
	public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; }
}

The reason for the change is that my original example was based on code from an older version of JNoSQL, and long IDs end up causing trouble when updating existing documents.

Also go to PersonRepository and modify it to use a String for the key:

package model;

import java.util.List;

import org.jnosql.artemis.Repository;

public interface PersonRepository extends Repository<Person, String> {
	List<Person> findAll();
}

 

Tweaking the Controller

The first step to adding in API methods doing this is to move the @Controller annotation down to just the methods that emit JSP responses (and adjust for the changed ID field while we're here):

package com.example;

import java.util.Random;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.mvc.Controller;
import javax.mvc.Models;
import javax.validation.Valid;
import javax.ws.rs.BeanParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;

import org.bson.types.ObjectId;
import org.jnosql.artemis.Database;
import org.jnosql.artemis.DatabaseType;

import model.Person;
import model.PersonRepository;

@Path("/people")
@RequestScoped
public class PersonController {
	@Inject
	Models models;
	
	@Inject
	@Database(DatabaseType.DOCUMENT)
	PersonRepository personRepository;
	
	@GET
	@Controller
	public String home() {
		models.put("people", personRepository.findAll()); //$NON-NLS-1$
		return "person-new.jsp"; //$NON-NLS-1$
	}
	
	@POST
	@Controller
	public String createPerson(@BeanParam @Valid Person person) {
		if(person.getId() == null || person.getId().isEmpty()) {
			person.setId(new ObjectId().toHexString());
		}
		
		models.put("person", personRepository.save(person)); //$NON-NLS-1$
		models.put("people", personRepository.findAll()); //$NON-NLS-1$
		return "person-created.jsp"; //$NON-NLS-1$
	}
}

Doing this shouldn't change the behavior of the app, and that's what we want.

Add Some API methods

Now, to be a proper REST API, we'll want a suite of Create-Read-Update-Delete methods using standard HTTP verbs. Add these methods to the class:

@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Person> list() {
  return personRepository.findAll();
}

@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Person getPerson(@PathParam("id") String id) {
  return personRepository.findById(id).orElseThrow(() -> new javax.ws.rs.NotFoundException("Could not find person for ID " + id)); //$NON-NLS-1$
}

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Person createPersonApi(@Valid Person person) {
  if(person.getId() == null) {
    person.setId(new ObjectId().toHexString());
  }
  return personRepository.save(person);
}

@DELETE
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public JsonObject deletePersonApi(@PathParam("id") String id) {
  personRepository.findById(id).orElseThrow(() -> new javax.ws.rs.NotFoundException("Could not find person for ID " + id)); //$NON-NLS-1$
  personRepository.deleteById(id);
  return Json.createObjectBuilder()
      .add("success", true) //$NON-NLS-1$
      .build();
}

@PUT
@Path("{id}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Person updatePersonApi(@PathParam("id") String id, @Valid Person person) {
  person.setId(id);
  return personRepository.save(person);
}

Here, we're taking advantage of JAX-RS's MIME-type-based routing: because our @Controller methods deal with HTML but these new methods declare that they're working with JSON, JAX-RS will route incoming browser visits to the controller and incoming API requests to the others.

Testing It Out

We can see this in action by trying out the API from the command line (or with a REST client app like Postman):

$ curl -i http://localhost:9091/javaeetutorial/resources/people
HTTP/1.1 200 OK
X-Powered-By: Servlet/4.0
Content-Type: application/json
Date: Sat, 16 Feb 2019 17:05:16 GMT
Content-Language: en-US
Content-Length: 246

[{"emailAddress":"api@test.com","id":"5c683fd40048ce11b5f6aee8","name":"API Test"},{"emailAddress":"foo@foo.com","id":"5c6841520048cea7c9f6c2d5","name":"Foo Fooson"},{"emailAddress":"foo@foo.com","id":"5c6841690048cea7c9f6c2d7","name":"API mod"}]

$ curl -i -X POST -H"Content-Type: application/json" http://localhost:9091/javaeetutorial/resources/people -d "{\"emailAddress\":\"foo@foo.com\",\"name\":\"Created with cURL\"}"
HTTP/1.1 200 OK
X-Powered-By: Servlet/4.0
Content-Type: application/json
Date: Sat, 16 Feb 2019 17:11:55 GMT
Content-Language: en-US
Content-Length: 89

{"emailAddress":"foo@foo.com","id":"5c68445b0048cea7c9402b85","name":"Created with cURL"}

$ curl -i -X PUT -H"Content-Type: application/json" http://localhost:9091/javaeetutorial/resources/people/5c68445b0048cea7c9402b85 -d "{\"emailAddress\":\"foo_mod@foo.com\",\"name\":\"Modified with cURL\"}"
HTTP/1.1 200 OK
X-Powered-By: Servlet/4.0
Content-Type: application/json
Date: Sat, 16 Feb 2019 17:12:30 GMT
Content-Language: en-US
Content-Length: 94

{"emailAddress":"foo_mod@foo.com","id":"5c68445b0048cea7c9402b85","name":"Modified with cURL"}

$ curl -i -X DELETE http://localhost:9091/javaeetutorial/resources/people/5c68445b0048cea7c9402b85
HTTP/1.1 200 OK
X-Powered-By: Servlet/4.0
Content-Type: application/json
Date: Sat, 16 Feb 2019 17:12:54 GMT
Content-Language: en-US
Content-Length: 16

{"success":true}

OpenAPI Documentation

OpenAPI is the boring-ified name of the standardized spec of Swagger, a mechanism for documenting REST APIs - kind of like what WSDL is for SOAP web services. This spec has become an important part of MicroProfile, the set of Java server technologies geared towards writing microservices that shares a lot of core technologies with Java EE. One of the niceties that MicroProfile includes is an automatic OpenAPI generator for JAX-RS services. There are a few things to add to our environment to enable this, but not too much.

To begin with, we'll have to enable the OpenAPI generator feature in Open Liberty (TomEE may have something like this; I don't know). To do that, open up the "server.xml" file (labeled "Server Configuration" in Eclipse's Servers view) and add "mpOpenAPI-1.0" to the feature list:

<featureManager>
    <feature>javaee-8.0</feature>
    <feature>localConnector-1.0</feature>
    <feature>mpOpenAPI-1.0</feature>
</featureManager>

Doing that alone will enable the API documentation, available at http://localhost:9091/openapi. However, if you look closely at the output, you'll see it's not exactly what we'd want: the GET operation for /resources/people points to our MVC home method, which it considers an unstructured string. It also lists the "helloworld" and "markdown" resources, and you can feel free to delete those classes outright - we won't be returning to them.

To fix this, first go to the project's "pom.xml" and add a dependency on the MicroProfile OpenAPI spec:

<dependency>
    <groupId>org.eclipse.microprofile.openapi</groupId>
    <artifactId>microprofile-openapi-api</artifactId>
    <version>1.1</version>
    <scope>provided</scope>
</dependency>

This is another one we can mark as "provided" since the implementation is included with the server.

Now, go back to the PersonController class, add an import line for org.eclipse.microprofile.openapi.annotations.Operation, and annotate the two MVC methods to mark them hidden from OpenAPI:

@GET
@Controller
@Operation(hidden=true)
public String home() {
  models.put("people", personRepository.findAll()); //$NON-NLS-1$
  return "person-new.jsp"; //$NON-NLS-1$
}

@POST
@Controller
@Operation(hidden=true)
public String createPerson(@BeanParam @Valid Person person) {
  if(person.getId() == null) {
    person.setId(new ObjectId().toHexString());
  }
  personRepository.save(person);

  models.put("person", person); //$NON-NLS-1$
  models.put("people", personRepository.findAll()); //$NON-NLS-1$
  return "person-created.jsp"; //$NON-NLS-1$
}

Now, if you refresh the /openapi output, you can see that it switched to the list method, and it knows that it outputs JSON, and includes a reference to the Person object structure at the bottom of the file.

There's a good deal more you can do with these annotations to customize the output, but it's nice to know that you can get an immediately-useful file that could be used to generate structured client libraries "for free".

Next Steps

Next, I think we'll dive into the world of Java EE authentication, which will be a very-different experience from what we're used to with Domino, for better and for worse.

XPages to Java EE, Part 10: Data Storage

  • Feb 15, 2019

How you store your data in an application is a potentially-huge topic, which is one of the reasons I've pushed it off for a while.

Designer's Curse

This is particularly the case because of the habits we learned over the years as Domino developers. One of the most grievous wounds Domino inflicted on us was an encouragement to always write directly to the data-storage implementation objects - forms and views for Notes client design or the lsxbe/lotus.domino classes for LotusScript and Java. They work, sure - fetching a document, setting fields, and storing it will get the job done - but it's an extremely-bad habit to work without a model framework and some level of indirection. Various people, including me, have made valiant efforts to add a model/DAO layer into XPages development in particular, but they've met with little uptake outside the individual developers who wrote them.

Fortunately, Java EE does not suffer from this specific brain poison, and it has a long history of abstracted data access, primarily via the Java Persistence API, traditionally backed by a JDBC driver for a SQL database. The point of an API like that is to let you write your model objects with just some annotations to explain to JPA bits about how it should be stored, and JPA will take care of the dirty work of actually mapping data types, writing queries, fetching data, and so forth.

JNoSQL

We won't be using JPA for this example, though. Instead, we'll be adding our second incubating spec: JNoSQL. JNoSQL is intended to be essentially "JPA for NoSQL", a largely-rethought API that won't crash into the hackiness of Hibernate's valiant attempt of re-using JPA directly. JNoSQL is currently slated for standardization as part of Jakarta EE and is under active development, but reached a point a while ago where it's good for use.

However, while there's technically a Domino JNoSQL driver that I put together last year, it's more of a POC than a real thing, and we'll skip it for this. For my uses, I've been using Darwino, which does have a splendid JNoSQL driver, but this series isn't the place to go through getting set up with that. For simplicity's sake, we'll be using MongoDB, which is quick to set up and is probably the furthest-developed driver in core JNoSQL.

MongoDB

So, to start out with, install MongoDB somewhere locally. This differs system-by-system - on Linux and macOS, I think it's available with package managers, or for any OS you can download an installer from their site.

Once it's installed, create a database named "exampledb" and a collection within it named "Person", as seen here with Compass, the standard admin app.

MongoDB collection configuration

Add the Driver

In your project's "pom.xml", add the JNoSQL document DB packages and MongoDB driver to your dependencies block:

		<!-- JNoSQL -->
		<dependency>
			<groupId>org.jnosql.artemis</groupId>
			<artifactId>artemis-core</artifactId>
			<version>0.0.7</version>
		</dependency>
		<dependency>
			<groupId>org.jnosql.artemis</groupId>
			<artifactId>artemis-document</artifactId>
			<version>0.0.7</version>
		</dependency>
		<dependency>
			<groupId>org.jnosql.artemis</groupId>
			<artifactId>artemis-validation</artifactId>
			<version>0.0.7</version>
		</dependency>
		<dependency>
			<groupId>org.jnosql.diana</groupId>
			<artifactId>mongodb-driver</artifactId>
			<version>0.0.7</version>
		</dependency>

For reference, "artemis" in JNoSQL terms refers to the mapping API - the annotations we're going to use - while "diana" refers to the driver portion.

Create the Configuration Class

Create a new class in the model package called DocumentCollectionManagerProducer:

package model;

import java.util.Collections;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;

import org.jnosql.diana.api.Settings;
import org.jnosql.diana.api.document.DocumentCollectionManager;
import org.jnosql.diana.api.document.DocumentCollectionManagerFactory;
import org.jnosql.diana.api.document.DocumentConfiguration;
import org.jnosql.diana.mongodb.document.MongoDBDocumentCollectionManager;
import org.jnosql.diana.mongodb.document.MongoDBDocumentCollectionManagerFactory;
import org.jnosql.diana.mongodb.document.MongoDBDocumentConfiguration;

@ApplicationScoped
public class DocumentCollectionManagerProducer {
	private DocumentConfiguration<MongoDBDocumentCollectionManagerFactory> configuration;
	private DocumentCollectionManagerFactory<MongoDBDocumentCollectionManager> managerFactory;
	
	@PostConstruct
	public void init() {
		configuration = new MongoDBDocumentConfiguration();
    // Modify this if MongoDB is not on localhost
		Map<String, Object> settings = Collections.singletonMap("mongodb-server-host-1", "localhost:27017"); //$NON-NLS-1$ //$NON-NLS-2$
		managerFactory = configuration.get(Settings.of(settings));
	}
	
	@Produces
	public DocumentCollectionManager getManager() {
		return managerFactory.get("exampledb"); //$NON-NLS-1$
	}
}

There's a lot there, but fortunately some of it builds on the CDI producer/scope functionality we encountered earlier. What we're doing here is setting up an application-wide bean that produces a configuration object for JNoSQL to use - specifically, using MongoDB. In a real situation, you'd want to externalize the settings in some way, but putting it into the code will do for now. The getManager() method will be used behind the scenes when JNoSQL asks the environment for a document-database manager.

Create the Model

Create another new class in the model package, this time named Person:

package model;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.ws.rs.FormParam;

import org.jnosql.artemis.Column;
import org.jnosql.artemis.Entity;
import org.jnosql.artemis.Id;

@Entity
public class Person {
	@Id("id")
	private long id;
	@Column @FormParam("name") @NotBlank
	private String name;
	@Column @FormParam("emailAddress") @NotBlank @Email
	private String emailAddress;
	
	public long getId() { return id; }
	public void setId(long id) { this.id = id; }
	public String getName() { return name; }
	public void setName(String name) { this.name = name; }
	public String getEmailAddress() { return emailAddress; }
	public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; }
}

This class uses JNoSQL's annotations to define an object that can be stored (@Entity), its unique ID field (@Id), and the fields contained in it (@Column, a name that matches JPA's SQL-based view of the world). You can also see that it includes the JAX-RS and validation annotations from the class we set up when learning about MVC. With the artemis-validation dependency we included, JNoSQL will, like JAX-RS, automatically enforce bean property constraints like this when saving, meaning we don't have to spent so much time dealing with validation logic ourselves.

Whether or not it's a good idea mix the JAX-RS and persistence annotations like this is something I'm not entirely sure about, but it'll work for our purposes.

Create the Repository

Create a new interface (not a class) in the model package named PersonRepository:

package model;

import java.util.List;

import org.jnosql.artemis.Repository;

public interface PersonRepository extends Repository<Person, Long> {
	List<Person> findAll();
}

You may be thinking at this point, as I originally did, that the next step will be to create an implementation class to do the work for this. Nope! This is where some real CDI voodoo comes into play: inside JNoSQL is a bean that produces "proxy" classes on the fly for Repository interfaces and figures out implementations of the methods based on their names, return types, and parameters. It's not magic - there are limits - but in cases like this it'll do what we'd otherwise expect to have to do ourselves.

Back to the PersonController

Return to the PersonController class we created before and rework it to use our newly-minted JNoSQL objects:

package com.example;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.mvc.Controller;
import javax.mvc.Models;
import javax.validation.Valid;
import javax.ws.rs.BeanParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;

import org.jnosql.artemis.Database;
import org.jnosql.artemis.DatabaseType;

import model.Person;
import model.PersonRepository;

@Path("/people")
@Controller
@RequestScoped
public class PersonController {
	@Inject
	Models models;
	
	@Inject
	@Database(DatabaseType.DOCUMENT)
	PersonRepository personRepository;
	
	@GET
	public String home() {
		models.put("people", personRepository.findAll()); //$NON-NLS-1$
		return "person-new.jsp"; //$NON-NLS-1$
	}
	
	@POST
	public String createPerson(@BeanParam @Valid Person person) {
		if(person.getId() == 0) {
			person.setId(new Random().nextLong());
		}
		personRepository.save(person);
		
		models.put("person", person); //$NON-NLS-1$
		models.put("people", personRepository.findAll()); //$NON-NLS-1$
		return "person-created.jsp"; //$NON-NLS-1$
	}
}

Add a Person List Tag

Back in the "Deployed Resources" section of the project, create a new directory beneath "WEB-INF" called "tags", and within that create a new file named "personList.tag":

WEB-INF/tags directory

Set the file contents to:

<%@tag description="Displays List&kt;model.Person&gt;" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %>
<%@attribute name="value" required="true" type="java.util.List" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<h1>People</h1>
<table>
	<thead>
		<tr>
			<th>ID</th>
			<th>Name</th>
			<th>Email Address</th>
		</tr>
	</thead>
	<tbody>
		<c:forEach items="${pageScope.value}" var="person">
		    <tr>
		    	<td><c:out value="${person.id}"/></td>
		    	<td><c:out value="${person.name}"/></td>
		    	<td><c:out value="${person.emailAddress}"/></td>
		    </tr>
		</c:forEach>
	</tbody>
</table>

This is our JSP equivalent of an XPages custom control, though all of the configuration is done inline instead of via XPages's auto-maintained .xsp-config side file.

Update the Person Views

Modify "person-new.jsp":

<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html>
<html lang="${translation._lang}">
	<head>
		<title>${translation.appTitle}</title>
	</head>
	<body>
		<h1>Create Person</h1>
		<form method="post" action="people">
			<dl>
				<dt>Name</dt>
				<dd><input name="firstName" required/></dd>
			</dl>
			<dl>
				<dt>Email Address</dt>
				<dd><input type="email" name="emailAddress" required/></dd>
			</dl>
			<input type="submit" value="Submit"/>
		</form>
		
		<t:personList value="${people}"/>
	</body>
</html>

Do similarly to "person-created.jsp":

<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html>
<html lang="${translation._lang}">
	<head>
		<title>${translation.appTitle}</title>
	</head>
	<body>
		<h1>Created Person</h1>
		<dl>
			<dt>First Name</dt>
			<dd><c:out value="${person.firstName}"/></dd>
		</dl>
		<dl>
			<dt>Email Address</dt>
			<dd><c:out value="${person.emailAddress}"/></dd>
		</dl>
		
		<t:personList value="${people}"/>
	</body>
</html>

Take It For a Spin

Launch the Liberty server and visit http://localhost:9091/javaeetutorial/resources/people. You should be able to add new entries, with the browser taking care of the client-side validation for you and JNoSQL and JAX-RS handling it on the server side. Best of all, the data should persist!

Updated UI with person listing

If you look at the database in Compass, you'll see entries there as well. JNoSQL mapped the Person class name to the "Person" collection in the database:

Data stored in MongoDB

Next Steps

In the next post, I plan to touch a bit on mixing MVC controller methods with JSON-based REST APIs, to bring these parts together into something that starts to approach a real application.

Update: Troubleshooting Note

One thing I encountered in my fiddling was an intermittent case where the server wouldn't load the app, instead complaining about an unsatisfied provider for the PersonRepository class. If you run into this, make sure you have a "beans.xml" file inside your "webapp/WEB-INF" directory in "Deployed Resources", and set its contents to:

<?xml version="1.0" encoding="UTF-8"?>
<beans bean-discovery-mode="all"
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"/>

This is the CDI configuration file. Though it's mostly empty, the critical part is bean-discovery-mode="all", which causes it to check all available providers in the classpath.

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.

Reforming the Blog in Darwino, Part 4

  • Jul 20, 2018

Last time, I went over my switch in tack for how I'm making the new version of my blog, and my overall focus on picking an interesting stack of JEE technologies. In this post, I'm going to start diving into the implementation of the UI, though I think that it will make sense to dedicate two posts to it.

The biggest decision I made with the UI side of this app is that I didn't want to make a client-side JS app. There's a reason they're so ascendant, and I find development with React or Stencil pretty enjoyable, but I wanted to go a different route here for a few reasons:

  • For a blog, a CSJS app is wildly overkill, and, in fact, would require extra work to fulfull one of the basic requirements of a blog, which is being web-crawler friendly.
  • I want to see how svelte I can make the client payload.
  • Skipping a JS framework (and a CSS one) is a great way to brush up on what plain HTML and CSS are capable of nowadays.
  • Unlike a typical Darwino app, my only target is a full-on Java web server, so I'm not held back on the Java side by the capabilities, say, of Dalvik on Android 4.
  • Part of me misses the simplicity of my early PHP days, albeit not the language.

The Java Side

I decided to go with the MVC 1.0 draft spec because it lets me write extremely focused code. Here is the controller for the home page:

package controller;

import javax.inject.Inject;
import javax.mvc.Models;
import javax.mvc.annotation.Controller;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

import model.PostRepository;

@Path("/")
@Controller
public class HomeController {
	@Inject
	Models models;
	
	@Inject
	PostRepository posts;
	
	@GET
	public String get() {
		models.put("posts", posts.homeList());
		
		return "home.jsp";
	}
}

Naturally, there's a lot of magic going on behind the scenes - there's tons of heavy lifting going on here by JAX-RS, MVC, CDI, JNoSQL, and Darwino - but that's the point. All the other components are off doing their jobs in their areas, while the code that provides the UI doesn't have to care about the specifics.

Things can get more complicated on the pages that actually have some functionality to them, but the code remains pleasantly focused. Take the handler for deleting posts:

@DELETE
@Path("{postId}")
@RolesAllowed("admin")
public String delete(@PathParam("postId") String postId) {
	Post post = posts.findByPostId(postId).orElseThrow(() -> new IllegalArgumentException("Unable to find post matching ID " + postId));
	posts.deleteById(post.getId());
	return "redirect:posts";
}

This adds another level of magic in the form of javax.security.annotation.RolesAllowed, but it's more of the good kind: even with no knowledge of the underlying frameworks, it's pretty clear what every bit of code is doing here. It's a refreshing bit of that Rails simplicity, just more compile-type-safe and much uglier.

Even beyond the minimal code is the cleanliness that this brings to the structure of the application: other than the img, css, and js paths, all of the routing within the application is done care of JAX-RS and MVC. It's not beholden to the folder structure in the project or to a Domino-style implicit app router.

JSP

JSP has been the prototypical Java HTML language for about 20 years, and it's had a rough upbringing. The early versions committed the PHP/XPages sin of encouraging you to put business logic right on the page, and it even still has the typical Java problem that it's tricky to find advice about using it that uses technologies added since 2005.

Still, when used properly, it can be a nice, clean templating language. Again from the main home page:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<t:layout>
	<c:forEach items="${posts}" var="post">
		<t:post value="${post}"/>
	</c:forEach>
</t:layout>

For an XPages developer, this is extremely comfortable. It's also very refreshingly elemental: there's no server-side persistence of the page, so everything is "load-time bound" and, with just HTML tags and core JSTL tags, nothing ends up on the page that you don't explicitly put there.

Ozark, the MVC implementation, also supports using JSF "Facelets" for the view portion, but JSP suits the task just fine.

HTML + CSS

It'd been far too long since I last really sat down and looked at what baseline HTML and CSS are like - in particular, I'd watched the rise of CSS Flexbox and Grid from afar, and never gave them a shot. Using components that generate their own HTML and pre-existing CSS frameworks to target with class names is all well and good, but it does leave you a bit disconnected from the fundamentals.

So, for this iteration, I tossed aside the very-nice Bootstrap framework I've been using, dusted off one of my old hand-built ones, and got to translating it into CSS Grid. This cut down on the page size enormously: I had already echewed Dojo by not using XPages, but this now also meant that I could ditch the core bootstrap.css, jQuery, and any jQuery plugins.

Beyond CSS Grid, have you seen how nice HTML forms are nowadays? Just looking at this post reveals how much is built in in the way of validation and different input types, even before you write a line of JavaScript.

Turbolinks

Having such a trimmed-down UI means that pages already load extremely quickly, but I figured this was also a perfect chance to try out a bit of clever tech from the team at Basecamp: Turbolinks. Turbolinks is a JS file that you bring into your app which then transparently takes over your in-app links to minimize the amount of rendering you have to do. Since the surrounding boilerplate of the app usually doesn't change between requests, it can figure out the "diff" between old and new and just replace the body. It's essentially like partial refreshes without the server knowing anything about it.

It's still technically inefficient to have the server render and transfer surrounding page elements that are just going to be discarded anyway. But, on the other hand, skipping that means that I don't have to write JavaScript handlers myself, use a full CSJS app framework, or keep state on the server side. The server just keeps doing what it does with a fully context-less request and the browser sorts it out. Basecamp's programmers are masters at the targeted deployment of kludges for maximum benefit.


In the next (final?) post in the series, I'll finish up with my "low-JS" experience and other lessons learned from this project.

Reforming the Blog in Darwino, Part 3

  • Jul 18, 2018

A good while back, I created a project structure for reforming my blog here in Darwino, but, as happens with low-priority side projects, it withered on the vine, untouched since then. Beyond just the "cobbler's children" aspect to it, I also lost steam due to a couple technology paths I initially headed down.

The first was basing the UI on Angular, which I've never really enjoyed working with. I'm sure I could have ended up with a decent result with it, but Angular always rubbed me the wrong way. And not just Angular: for a dead-simple UI like this, a full JS UI is just weird overkill.

The second was off in the other direction: I initially tried cramming a Rails app in the tree, which could be made to work, but it introduced so many weird edge cases outside of the problem at hand. That alone isn't the end of the world, but not much of what I'd have to solve to make that work would be transferrable elsewhere any time soon, so it'd end up a real time sink.

So, taking what I've learned since and the projects that I've been working on, I've decided to take another swing at it. Before I get into the implementation side, it will be useful to go over the technologies I did choose for the new form.

Java/Jakarta EE

I've recently become kind of enamored with the modern form of the Jakarta EE stack, and so I decided to use this as an opportunity to really dive in to what a blue-ocean small by-the-books Java app looks like nowadays.

JEE got a well-deserved bad rap over the years for its configuration complexity and general impenetrable-ness, but I've been very pleased to find that those tides have largely receded. It's all still there if you want it, but a fresh new app primarily consists of decorating a handful of Java classes with declarative annotations.

JEE consists of a series of individual specs, and building an app involves choosing which ones you want to use, plus (depending on which you choose) picking your app server target.

Tomcat

I originally gave a shot to adding enough OSGi metadata and bundles to target Domino, but decided quickly that it was just not worth it. The HTTP/servlet stack in Domino is just so old that, even if I got everything bound together, I'd still be fighting the platform every step of the way.

The better route was to put it aside and just run a modern Java app server. I went down the list of GlassFish, Payara, WebSphere Liberty (the nearest miss), TomEE, and WildFly, but each one ended up having some problem with either the dependencies I wanted or with their Eclipse integration. I ended up settling on good ol' reliable Tomcat. Tomcat itself isn't actually a JEE server, but it's kind of like a Raspberry Pi: it gives you the baseline for a Java servlet engine, and then you can cobble together your own EE stack on top of it by explicitly bringing in implementations. Though the final .war file is far less svelte this way, I found that this build-your-own method results in the lowest chance of being held back by the platform currently.

As an aside, Sven Hasselbach has been writing a very interesting series on running Jetty on top of the Domino JVM to achieve a similar end, albeit with Spring.

Darwino

For all the same reasons as when I set out on this journey originally, I'm using Darwino for the baseline. This lets me replicate in my existing blog data smoothly while getting the advantages of a superior backing database. I'm not making use of mobile clients or most Darwino services with this, but the baseline is nonetheless a step up, and fits in with a JEE app like a glove.

JNoSQL

I brought in the JNoSQL Darwino driver I wrote a little while ago to handle the model layer. JNoSQL is essentially JPA but reformed for NoSQL access - no cruft, no relational/NoSQL impedence mismatch, and designed to fit with current JEE technologies.

CDI

CDI is one such technology, and it's a very interesting one to work with. The whole "dependency injection" realm is a little fraught and, if my Eclipse UI error reporter is any indication, prone to bizarre errors, but the core concept is good and very useful. I've gotten it into the swing of using it both as the "managed bean" provider for the front end as well as the general service provider glue for the app. It still takes some getting used to, and the learning curve falls prey to a similar problem as when I was learning Maven: something about learning how it works makes you forget what it was like to not know, and so a lot of the answers online assume way more knowledge than a neophyte has.

Bean Validation

I've long been a fan of the Java bean validation API, and it's a clean fit here too: JNoSQL picks up on the presence of Hibernate Validator without configuration beyond the dependency and it just works. No muss, no fuss.

JAX-RS + MVC Spec

JAX-RS is at this point familiar territory for a lot of Domino developers, but I decided to use it as the underpinnings of the whole UI, in tandem with a draft framework called MVC 1.0. The latter's generic name doesn't really give much detail, but it's essentially a spec that enhances JAX-RS entities with knowledge of HTML templating frameworks, allowing you to write a very clear app structure. It's not a server-state-based framework like JSF, but rather a bit "closer to the metal", where you deal directly with the HTTP method cycle.

As I'll go more into in the "UI" post, it's been surprisingly refreshing to get back to basics in this way - JSF/XPages is often a bit conceptually easier to work with (at first) and client-side JS frameworks have some REST+JSON purity to them, but just "this server-rendered HTML page with no server state is everything you need" feels really good sometimes.

Admittedly, the MVC spec itself is in a weird place. It was originally a candidate for inclusion in Java EE 8, but was dropped in the final runup. It's possible that this will prove to be a kiss of death, but the spec is so small but functional that I don't feel bad about taking the risk of building an app on it.


That about covers the technology stack. When I get around to writing the next post, I'll go into some of the specifics about how I decided to set up the UI, which has been a fun experiment of its own. In the mean time, the active repository is up at:

https://github.com/jesse-gallagher/frostillic.us-Blog/tree/develop/frostillicus-blog

Another Project: XPages Jakarta EE Support

  • Jun 3, 2018

In my dealings with JNoSQL recently, I’ve been delving more into the world of modern Jakarta EE/Java EE/J2EE development, particularly the magic land of CDI.

The JEE stack tends to be organized as a collection of specs and implementations, many of which are really independent of each other and the underlying platform, making them pretty portable onto any reasonably-recent JVM. Now that Domino is actually on a reasonably-recent JVM, that makes it a workable target! So I decided to create a side project to bring some of JEE to XPages.

XPages has always been “sort of Java EE” - you don’t really have the full stack, and it’s far behind on the components that it does have, but a lot of the concepts are there. Of particular interest are managed beans and expression language.

CDI and Managed Beans

The XPages stack contains what amounts to a priomordial version of CDI. Since the release of XPages, JSF improved on the original faces-config.xml declaration method to add annotation-based declarations, and then CDI is something of a codification and expansion of that into the full Java world.

My project uses the Weld reference implementation of CDI to create a CDI context for each XPages app that opts in, allowing it to use annotations on classes to declare beans and properties:

@ApplicationScoped
@Named // or @Named("applicationGuy")
public class ApplicationGuy {
    public void getFoo() {
        return "hello";
    }
}

These can then be used like normal managed beans in an XPage:

<xp:text value="#{applicationGuy.foo}"/>

The project’s README contains some further examples.

I went with the Java SE implementation of Weld instead of the pre-built servlet or OSGi packages since those are a little too smart for this use: they pick up on the fact that they’re in a JSF environment, but expect newer versions of the servlet spec and JSF.

Expression Language

Since its original release, EL went through a similar standardization process as CDI and is now at version 3.0 and is distinct from JSP and JSF. As anyone who has tried to call a method on a bean in EL has found out, the XPages EL implementation lags pretty far behind, at the JSF 1.0/1.1 level. Since that time, it sprouted parameters and “projection” and is essentially a tiny scripting language now.

My project uses GlassFish’s EL implementation to outright replace the stock EL interpreter for apps making use of it. I added some affordances to IBM’s customized data support, so it’s intended as a drop-in replacement:

<xp:text value="${dataObjectExample.calculateFoo('some arg')}"/>

<xp:text value="#{el:requestGuy.hello()}"/> 

Note the “el:” prefix in the runtime-bound expression: that’s to get around Designer’s validation of runtime EL expressions.

So… Why?

That’s a good question! The first two reasons are “because it’s fun” and “to learn more about JEE”, but there’s also practical value for this sort of thing.

XPages is moribund, and that leaves Domino developers with a few options:

  • Go back to LotusScript. The iPad Notes client makes this a terrifyingly-practical option, but it’s soul death.
  • Go to JavaScript (or another platform). This is another route HCL is pushing, and it’s entirely valid: Node is a great platform with excellent support and momentum.
  • Go to modern Java.

For anyone who has invested a lot of time and brainpower in XPages over the years, that last one particularly appealing, and projects like this can help you get there. If you have a large XPages code base, as I do with one of my clients, it makes a lot more sense to work on that in such a way that it gradually becomes less XPage-dependent while avoiding the trap of a full rewrite in another language.

Many of us have already done something of this sort: JAX-RS is another JEE standard, and the Wink implementation in the Extension Library, though also aging, accomplishes this same sort of task. Especially if your services don’t reference Wink explicitly and write just to the spec, they are very portable.

That portability - of code and skillset - is critical. Say you have a class like this:

import javax.inject.Inject;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/issues")
public class IssuesResource {
    @Inject IssueRepository issueRepository;

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response get(@QueryParam("category") String category) {
        return issueRepository.find(category).stream()
            .map(this::doSomething)
            .skip(3)
            .collect(this::toResponse);
        }

‚Äč     // ...
}

Which Java platform is that targetting? What’s the data storage mechanism? Who cares? This class certainly doesn’t. That could just as easily be Domino reading from an NSF or (as is actually the case in the example’s source) Tomcat with Darwino.

What’s Next?

Truthfully, maybe not much. Though JEE contains a whole raft of technologies, these two were the ones that scratch my immediate itch. We’ll see, though - the skill portability of erstwhile XPages developers is critically important, and I think that this is another one of the paths that can get us where we need to go.

Lessons From Writing a JNoSQL Driver

  • Dec 30, 2017

The other day, I decided to start up a side project to write an app for my Stars Without Number game in Darwino. Like back when I wrote a forum/raiding app for my WoW guild, I like to use this kind of opportunity to try new technologies and flesh out my skills in existing ones.

One such tech I've had my eye on for a bit is JNoSQL, which is a framework for integrating with NoSQL databases in Java. It's along the lines of Hibernate OGM, but intended to avoid the pitfalls of the relational/NoSQL that came with trying to adapt JPA directly to NoSQL databases. JNoSQL promised to be much easier to implement for a new database, so I decided to give it a shot.

JNoSQL

JNoSQL is split into two paired components, cleverly named Diana (the driver side) and Artemis (the model/integration side). The task of writing a driver for a new database is pretty well-contained: pick the database type(s) you want to implement (out of key/value, column, document, and graph) and implement about half a dozen interfaces. This is in stark contrast from when I took a swing at writing a Hibernate OGM driver, where the task was significantly more daunting. The final result is only ten Java files, with a chunk of them being utility classes for code organization.

It's a young project - young enough that the best version to run right now is 0.0.4-SNAPSHOT - but it functions well and it's been taken under the wing of the Eclipse foundation, which builds some confidence.

Implementation

Though the task was small, there were still a couple initial hurdles to getting going.

To begin with, I decided to start with the Couchbase driver - this certainly made the overall task easier, since Couchbase's semantics are very similar to Darwino's, but it also meant that I had to be wary of which parts of the codebase were really about implementing a Diana driver and which were Couchbase-isms. Fortunately, this was much easier than the equivalent work when I adapted the CouchDB Hibernate OGM driver, which was a sprawling codebase by comparison.

More significantly, though, it's always tough coming in to modify a codebase written by a single person or small team and learning as you go. The structure of the code is clean, but not quite my normal style (in part because Domino kept me from diving into Java 8 streams for so long), and I also had to ramp up quickly on the internal concepts of Diana. Fortunately, this was mostly easy, since the document-DB driver scaffolding is purpose-built, the hooks are straightforward and the query semantics were extremely easy to adapt. The largest impediment was getting used to the use of the term "Document", which internally refers to a key/value pair, while "DocumentEntity" is closer to the expected meaning.

Like the core implementation, the test suite I adapted from Couchbase was also pleasantly svelte, covering the bases without being an onerous nightmare to convert. Indeed, most of the code I added to it was the Darwino app scaffolding just for the test runtime.

Putting It Into Practice

Once the driver was written, I was hit by a bit of a personal curveball when I went to implement some actual data models. The model side, Artemis, is heavily wrapped together with CDI, which is a Java EE thing that, as I gather, handles managed beans, separation of implementation, and variable injection. This is a pretty normal thing for Java EE developers, but XPages's "don't call it Java EE" environment didn't introduce me to this aspect. As such, the fact that the documentation just kind of casually tossed around CDI terms and annotations threw me for a bit of a loop trying to determine what was what was required and what was just an idiom.

I eventually determined that I could use the reference implementation, Weld, without necessarily going whole-hog on Java-EE-everything. I'm a bit wary of what this bodes for whether I'll be able to use JNoSQL in Darwino on mobile devices, but I'll cross that bridge when I come to it. Once I got a bit of a handle on what Weld is and how to use it in unit tests (hint: make sure you have beans.xml files!), I was able to start writing my model objects and testing them.

Doing It Again

The fact that the bulk of my implementation work ended up being on the app side with CDI goes to show that the Diana driver model really shines. It got me thinking about how difficult it would be in the future, say to write a driver for Domino. There'd be some hurdles - Domino's lack of nested objects and antiquated querying mechanisms would need replacing - but the core task wouldn't be too bad. I don't know if I'd have a need for it, but it's nice to keep in mind as potential future small project.

All in all, I'm optimistic about the use of this. I'd love for Darwino to integrate as smoothly as possible into whatever standard environments it can, and this is one more step in that direction. I'll know as my side app takes shape how much this ingrains itself into my actual work.