XPages to Java EE, Part 5: Web Pages

Thu Jan 24 12:19:20 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?

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

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

Translation File

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

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

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

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

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

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

Index Page

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

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

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

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

Replace the new file's contents with this:

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

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

Translation Bean

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

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

package bean;

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

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

@RequestScoped
public class TranslationBean {
	@Inject
	HttpServletRequest request;

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

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

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

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

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

Loading It Up

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

The HTML will be pleasantly sparse:

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

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

Next Steps

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

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

Commenter Photo

Karl - Fri Mar 01 19:25:22 EST 2019

Great series!!  What is preferred jsf implementation?  Myfaces vs Mojarra.  Jakarta uses Mojarra; however open liberty has Myfaces as default implementation.  Reasoning?   Preferred UI library?  Primefaces, etc.  Jakarta have any plans to advance UI components in JSF?  Hope you keep the series going.

New Comment