Showing posts for tag "javaee"

Concept Proven: A Complex Production XPages App Running Outside Domino

Mon Oct 07 13:13:43 EDT 2019

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

Around the start of the year, I took a little time to see if I could get XPages as it exists today running outside of a Domino server, specifically inside Open Liberty. I met with a good deal of success, finding that I could run stripped-down apps "freely" inside a normal WAR web app, and I could run full-fledged NSF-hosted apps using the LCDEnvironment container-within-a-container technique that normal XPages uses.

Since then, the prospects had been percolating in my mind, including coming back around a few months later to get XPages running on iOS and Android by way of Darwino. At the end of that post, I mused a bit about what a proper setup would look like, which would be essentially taking XPages, custom controls, and supporting resources and putting them into a Maven-structured webapp.

This past week, I decided to put WoW Classic aside for a bit and put some evening-and-weekend time into seeing if I could my get client's huge, 500-XPages-and-CC, plugin-backed, JAX-RS-heavy app working in this setup. And, like before:

Short Answer

Yep!

Long Answer

Building on what I had before, there were some medium- and large-scale hurdles I had to overcome:

  • Hook up the remaining Servlets and listeners at the right times
  • Figure out what to do about transpiling XSP source
  • Add and adapt the remaining required IBM Commons Extensions
  • Tweak the OSGi bridge for more bundle-like behavior and remove Equinox dependencies in our code
  • Make the stack have a Notes runtime, but not think it's too much like Domino
  • Adapt Java EE standards use to ensure it'd work with different implementations

A lot of this work ended up being finding the right little bit to tweak or add - an environment variable here, a META-INF/services file there - but a couple of the topics warrant expansion.

App Legwork

The core of what made this possible was a combination of coincidental and intentional work I had been doing in the main app for a good while. The first big part was that I had started bringing in components of my separate XPages Jakarta EE Support project, in particular bean validation and JAX-RS 2.1. We had previously used an older version of Hibernate Validator, and we were using the ExtLib-provided Wink for a good while to build out our REST services. Moving to RESTEasy's JAX-RS 2.1 implementation not only let us use the newer features it provided, but also let us set aside the Wink-isms we had been using in a couple places in favor of what became standard after Wink went moribund.

I also stripped out as many Equinox-isms as I could that I had made assumptions about over the years, such as removing home-brewed Equinox extension points in favor of portable IBM Commons extensions and reducing our use of Require-Bundle in favor of Import-Package, which pointed out all the areas where we depended on a specific implementation of a standard as opposed to just the cross-server spec.

Notes Runtime

One of the pleasant things I found out in my original experiments was that, while a lot of the newer and more-complex components of the XPages stack end up having some assumptions about the presence of a Notes or Domino environment, there's no dependency on nHTTP specifically. As long as the stack can call into the lotus.domino and NAPI classes, it's happy.

Really, the only thing I had to tiptoe around was making sure that I didn't include the LCDEnvironment stuff and its associated platform assumptions. At one point, I did investigate whether I could use that and make the running web app just another "module" like an NSF - there's even partial support classes like FileModule for this kind of thing in a "mashupmaker" package - but I ran into too many assumptions about the environment and class hierarchies that way. It's a bit of a shame, since that would have allowed transparently referencing NSF-housed apps in the same server, but that was only a "nice to have" anyway. Plus, it would have had the down side of keeping everything within the LCD wrappers, which do things like report the environment as Servlet 2.5 no matter how they're running (which is, horrifically, an upgrade over the underlying 2.4 on Domino).

XSP Source

My original experiment and my bootstrapping here involved copying the generated Java xsp.* files from Designer into the src/main/java build path of the Maven project, which are then picked up by the CompiledPageDriver used by the XPages runtime. This works, but it's not exactly developer-friendly. To make it in any way practical, I'd need to be able to continue working with the XML source like in Designer.

The trouble here is conceptually similar to the impediment to incremental compilation in the ODP Compiler: due to the way XSP Libraries work, they require not only the presence of the full classpath to know what components are available, but also an active running Java application. They can't just be derived statically - this is why you have to install library plugins into Designer-the-application.

However, I had a distinct advantage here: though I didn't have a running app at editing/compile time, I sure would have a running app while the app is, uh, running. And that is a problem I did solve in the ODP Compiler, thanks to the Bazaar's hooks into the XSP interpreter inside the XPages stack. I realized that I could implement a FacesPageDriver that received requests for pages and compiled them on the fly. The interface is very simple: it contains only one method, which takes a FacesContext and a page name (like "/foo.xsp") and returns a FacesPageDispatcher, which is the obliquely-named interface implemented by the translated xsp.* Java classes.

Really, this could be anything; it's not actually tied to the Java translation and compilation process at all, and could be something like a live translator of XSP into spitting out UIComponent objects on the fly, which is something I considered. Though the use of compiled classes is an implementation detail, I ended up deciding to still piggyback on that, since a dynamic interpreter would have extra legwork to do to make sure the behavior was the same, whereas using the translator would guarantee the same results as if they were compiled the normal way. In practice, the main differences between my code here and the code in the ODP Compiler is that I could use the existing component registry from the running app and that I ended up compiling the classes as Groovy source instead of Java. I did the latter because the Groovy in-memory compiler didn't require the same kind of classpath crawling that the Java compiler does, and which had ended up being a major performance sink in practice. Groovy is almost a strict superset of Java syntax, so it only took a little bit of tweaking to the generated source to make it work - tweaking that could be done simply since the problem domain is so small.

Liberty-Specific Gotcha

Though I'm still smitten with Open Liberty as my Java host of choice, I did pull my hair out a bit over some of the side effects of it. Specifically, I ran into trouble when having the JSP feature enabled (which is on by default), where it would load up com.sun.faces.config.ConfigureListener much earlier in the process than it's supposed to be. It's something to do with an optimization for when you have real JSF enabled as well, but, since IBM didn't rename the core packages, Liberty picked up on the presence of it and kicked it off on server start, instead of during app load when it's expected.

Fortunately, Liberty's architecture is such that, if you don't choose to enable a feature, it's entirely absent at runtime, so there was a clear workaround. It's a bit of a shame, since going from XSP ? JSP is a legitimate potential path, but it's not the end of the world. Additionally, there's nothing Liberty-specific in my approach here. I haven't tried it, but the same app should work in Tomcat (if you bring in some standards implementations) or in another JEE server like Glassfish.

The Results

After wrangling with this stuff enough, though, the results were ideal: the full app, with all its dynamic content, runtime component additions, use of home.xsp/foo/bar path info shenanigans (its own hurdle in the Servlet world), dependency on ODA and half a dozen other XPages Libraries, and its plugin-served resources works just as it does on Domino. And, though some of the runtime setup was a bit hairy, the app itself is pretty svelte and straightforward. All the Java code is where it's expected to be, resources in src/main/webapp show up like you'd want, and it all just acts like it should.

The Future

So now I have an odd conundrum. I prefaced my post in January by saying that I didn't plan to do anything with the experiment, but now I'm looking over a precipice where I could theoretically plop the WAR file into the Domino Open Liberty Runtime, add a redirection rule to point to it, and call it a day. I certainly don't plan to, since there could be any number of weird problems with this and the app still points back to normal classic Domino web resources in some places, but now there's a dark voice whispering into my mind. "No more Designer," it says. "No more Tycho, or writing OSGi plugins just to get a third-party library to work nicely. No more Java policy nonsense. No more Servlet 2, or missing Javadoc, or the server not loading pages because the wrong logging JAR went into jvm/lib/ext. You could be free!" The dark voice makes a good case, I'll give it that. We'll see.

Bitwise Operators

Sat Apr 06 16:11:00 EDT 2019

Tags: javaee
  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

In the "Java Hiccups" post, I briefly mentioned this little tidbit:

(short)Integer.MAX_VALUE == -1   // true

This fact betrays a lot about how numbers are stored internally in most languages. Some of those details, like the fact that the specific method is called two's complement, are fully in the range of "computer science" stuff - but it can be handy to know about a couple ways you can put this sort of thing to use.

For our purposes, let's work with the short data type in Java, because it's painfully important to Notes. "Short" is called such because it's smaller than a standard integer type in a given language. In some languages, like C, the length of core data types like this is sometimes tied to the bitness of the processor, but in Java they're consistent across everything. Specifically, short in Java is 16 bits long. Let's take the number 21,038, which is represented in binary as:

0101 0010 0010 1110

That's two bytes, and each byte is broken up into two groups of four bits each because it turns out to be helpful visually and because each "nibble" there can be matched to a single hexadecimal character (522E in this case). This is the most common way you'll see binary written when you start getting into this sort of thing.

So I mentioned casting in the previous post, and what casting does with primitive integer types like this is to chop off the bits that don't fit. If you cast the above value into a byte, it'll chop off all but the ending 8 bits, giving you:

0010 1110

Which is 46. If you cast it to a larger type, such as int (32 bits in Java), it just adds some zeros to the front:

0000 0000 0000 0000 0101 0010 0010 1110

Which is still 21,038, but now it takes up twice as much memory.

For our uses, this stuff matters immediately in two ways: it represents the limits of some data storage and it allows us to manipulate numbers with bitwise operators.

Storage Limits

If you max out the bits in a 16-bit integer, you get 1111 1111 1111 1111, and this value is either -1 or 65,535 (64k) depending on whether or not the value is considered "signed" by the code using it. When it's "unsigned", a 16-bit integer can represent between 0 and 65,535; when it's "signed", its range is -32,768 to 32,767 (32k). Java only has "signed" types, which is why Short.MAX_VALUE is 32k and not 64k. C, on the other hand, lets you choose in your code which type you want to use.

The Notes C API uses a couple type names to represent consistent sizes across different platforms, and the one that's important here is WORD: a 16-bit unsigned integer. This is used in, for example, the function used to set the value of a text item in a note:

NSFItemSetText(
  NOTEHANDLE  hNote,
  const char far *ItemName,
  const char far *ItemText,
  WORD  TextLength)

That WORD at the end there is where you tell the API how much text you're providing, and is thus capped at 64k - and is why you can store 60k of text in a non-summary text field but not 70k. As to why summary data is limited to 32k and not 64k, I'm guessing that either there's a signed value in there somewhere or that last bit was needed for something else.

If you look over the list of Notes limits, you can see this reflected all over the place, along with a few 8-bit (0-255) limits for good measure.

Bitwise Operators (for real this time)

The term "bitwise" refers to a handful of operators that deal directly on the bits of a number. Java takes a cue from C here and provides &, |, ^, ~, <<, >>, and >>>. These all have their uses, primarily for really-low-level stuff and efficiency, but we mainly care about & and |. These two may have bitten you in the past because of their similarity to && and || - and in particular because Formula Language uses the single-character versions to mean what Java means by the double-character ones. They also kind of work the same way, but aren't really the same.

To see how they work, let's take our original starting number, 21,038, and pair it up with another value, 5,000:

0101 0010 0010 1110
0001 0011 1000 1000

Visualizing the numbers in binary and stacked like this comes in extremely handy when it comes to dealing with bitwise operators. We'll start with &, or "bitwise AND". What this operator does is take two numbers and return a number where the matching slots in each one both contain a 1. So, in this case, it results in this internal math:

0101 0010 0010 1110
0001 0011 1000 1000
===================
0001 0010 0000 1000

Which corresponds to 4,616.

The | operator, or "bitwise OR", will provide a result where either of the original numbers has a 1 in the slot. In this case:

0101 0010 0010 1110
0001 0011 1000 1000
===================
0101 0011 1010 1110

Or 21,422.

It's pretty rare that you want these operators for the actual numerical values, though. What they're pretty much always used for are "bit fields", an extremely-efficient way to store a set of related flags. Going back to the Notes API, the NSFItemAppend function (a generic way to add an item value) has a parameter WORD Flags, that matches up to a number of properties that you can assign to an item. In the C source, they're written as hexadecimal values, but I've added in the binary versions here:

#define	ITEM_SIGN          0x0001   // 0000 0000 0000 0001
#define	ITEM_SEAL          0x0002   // 0000 0000 0000 0010
#define	ITEM_SUMMARY       0x0004   // 0000 0000 0000 0100
#define	ITEM_READWRITERS   0x0020   // 0000 0000 0010 0000
#define	ITEM_NAMES         0x0040   // 0000 0000 0100 0000
#define	ITEM_PLACEHOLDER   0x0100   // 0000 0001 0000 0000
#define	ITEM_PROTECTED     0x0200   // 0000 0010 0000 0000
#define	ITEM_READERS       0x0400   // 0000 0100 0000 0000
#define ITEM_UNCHANGED     0x1000   // 0001 0000 0000 0000

So you can see that each flag there has a distinct slot filled in that each other doesn't (you can also see, like missing teeth, the bits that are probably obsolete or undocumented features). If you want to create an item that is a signed, sealed, summary, readers item, you'd do this:

WORD flags = ITEM_SIGN | ITEM_SEAL | ITEM_SUMMARY | ITEM_READERS

…which will result in this bit of internal math:

0000 0000 0000 0001
0000 0000 0000 0010
0000 0000 0000 0100
0000 0100 0000 0000
===================
0000 0100 0000 0111

This is extremely efficient, both because you can store a bunch of information in just 16 bits, but also because working with these bit fields is baked into processors at the lowest level. There's not much you can do on a computer that's faster, in fact.

When you have a value like this, you can query it for whether or not a given value is set by using the AND operator:

flags & ITEM_SUMMARY

This will result in:

0000 0000 0000 0100

…which is the same as the value of ITEM_SUMMARY itself, since that one slot is the only bit in common. Conversely, if you check:

flags & ITEM_PROTECTED

…you'll end up with zero, since the flag doesn't match.

Use in Java

Most of the time, you don't have to think too much about the bits that make up numbers in Java, but they creep up from time to time. Generally, the main situations where they arise are when you're dealing with a low-level API or with code written by someone who spent a lot of time with C and deeply internalized its efficiencies.

For an example of the former, take a look at the com.ibm.designer.domino.napi.NotesNoteItem class in IBM's NAPI. It contained a method called int getFlags(), which returns exactly the value we were talking about above. If you get your hands on a summary item this way, you can do this to tell if it's a summary item:

(item.getFlags() & 0x0004) != 0

Note the extra != 0. While the operation involved is the same as in C, C lets you treat any non-zero integer value as a boolean true, while Java forces you to perform an actual boolean operation.

For an example of the latter, turn your eyes to the DefaultColumnDef class used in xe:dynamicViewPanel generation and customization, a snippet of which is:

public static class DefaultColumnDef implements ColumnDef {
      public static final int FLAG_HIDDEN         = 0x000001;
      public static final int FLAG_LINK           = 0x000002;
      public static final int FLAG_ONCLICK        = 0x000004;

      public int flags;
  
      public boolean isHidden() {
          return (flags&FLAG_HIDDEN)!=0;
      }
      public boolean isLink() {
          return (flags&FLAG_LINK)!=0;
      }
      public boolean isOnClick() {
          return (flags&FLAG_ONCLICK)!=0;
      }
}

This could also be represented as a bunch of boolean properties on the object or, most idiomatically, an EnumSet, but using a bitmask is slightly more space- and CPU-cycle-efficient. Slightly. The difference isn't enough to even think about normally, but can become worth it in cases where the code is called so often that tiny efficiencies can make a difference.

This whole topic is the sort of thing that is normally so many layers of abstraction below where we work that it's basically invisible, but it's definitely good to at least know the basics for the times when it does come up.

XPages to Java EE, Part 13: Why Do This, Anyway?

Fri Mar 01 11:01:11 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?

In the introductory post to this series, I started by saying that I've come around to the idea that Java EE (and its kindred technologies) is the future for Java development with Domino, and I think it's worth taking some time to make the case that you should think so too.

A lot of it starts with a nagging question:

Is XPages Dead?

Speaking very strictly, no. XPages remains a component of a commercial product and so bug reports receive attention and fixes as they occur, and presumably all of the many problems the platform is bound to run into as the world evolves will also be addressed.

However, I think the more important question is:

Does It Even Matter If XPages Is Technically Not Dead?

At this point, XPages has, for almost its entire existence inside Domino, been "living" the peculiar kind of undeath that afflicts enterprise software. This is the sort of undeath you could see in, for example, IRIX, which had its last major release in 1998 but was "supported" with maintenance releases for another eight years. XPages has similarly had a few new features since the initial ExtLib release in the 8.5.2 era era - such as the Bootstrap renderkit and some quality-of-life bits - but it's clearly been in maintenance mode for a while. It's been a reactive type of maintenance, too: since XPages doesn't have the Notes-client-app advantage of existing in a controlled environment, XPages development has been increasingly a story of something breaking in some browser and harassing IBM or HCL until there's a fix.

"But wait," you might say, "HCL is going to be in charge now, and look how they're revitalizing the core of Domino! Maybe they'll do the same for XPages!" And, well, maybe they will. I doubt it, though - the core team they brought over isn't involved with XPages, and in general IBM and HCL seem to think so little of it that they don't capitalize it correctly in slides. HCL's development strategy seems to (defensibly) focus on porting the Notes client to other platforms and encouraging developers to either crawl back to LotusScript or to use development stacks that HCL isn't on the hook for, like Node.

And, even if they did staff up to enhance XPages, would it be wise to depend on that? It would still be a single-vendor stack using technologies (OSGi) and idioms (server-side page state) that work but aren't the way the wind is blowing. I would expect that any renewed push would be short-lived.

Okay, Grumpy Gus, Why Is Java EE Any Better?

There was a period in the recent past where Java EE was hitting some similar trouble: Oracle largely lost interest in Java EE (and Java in general, to a lesser extent) and development slowed. However, because so much was open source and (critically) the development pool was so much larger, things kept moving along, with the insurgent group of MicroProfile building new technologies. The transfer of Java EE to Eclipse has proven to be a blessing as well, with the community taking up the mantle splendidly.

As with anything, there's no absolute guarantee of a future path, but JEE has the critical mass that XPages doesn't, with community members and companies emotionally and financially invested in its future. There's no one company whose loss of interest would doom the whole thing, even the Java rump state at Oracle.

And, in the mean time, the technology is just better. You can use current versions of Java, new web technologies are adopted immediately, the IDEs are significantly more stable and featureful, the whole stack has source and Javadoc readily available, the surrounding tooling is better, the modern APIs are simpler and more descriptive, and so forth. Even though XPage's cousin, JSF, has lost some interest, it has evolved significantly past the point where XPages forked away - and is also just one of many good options for app development.

This Is The Bridge We Were Promised

When XPages was ported into Domino, one of the ancillary features for developers was that it would provide a path to the "real" development world, out of our abusive cell of Domino's legacy web stack. It meant being able to consume common Java libraries more practically than in Java agents, extending the capabilities of the platform ourselves, and using development practices that are closer to the rest of the world.

And, to a large extent, these promises came true. We've had the ability to work with the Servlet spec directly, we've been bringing in libraries like Poi with only medium-sized hurdles, and we've been able to (kind of) break the mental binding between the UI and data storage.

Now it's time to truly cross the bridge. There's still a case to be made for writing new XPages applications for now, but every line of XSP markup should be acknowledged as new technical debt. At this point, you should either start working towards Java EE or have a clear plan for how you're going to get there. It doesn't have to be Java EE: there's a lot to be said for taking up HCL on their suggestion to write Node apps, and there are other Java and non-Java frameworks out there that are actively advancing. Regardless of your choice, if you don't choose something, your development will remain stunted and you'll be at a near-guaranteed risk of some critical security problem showing up in an old Dojo version or some other part of the stack and having to clamor for an emergency fix that would otherwise be a one-line pom.xml or package.json tweak (if needed at all).

It's also just very pleasant - give it a try.

XPages to Java EE, Part 12: Container Authentication

Wed Feb 20 12:24:56 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?

Coming from Domino, we're both spoiled by the way it handles users and authentication. The server comes with an implicit directory far removed from the app, and so we just use that. Moreover, the HTTP "container" handles authentication for us: we configure whether we want HTTP Basic auth, simple session auth, LTPA, or SAML (I guess) authentication at the server/web site level, also far from the app. Then, in the application, we just set up an ACL in the DB or XPage and reader/author fields on notes and let the server take care of it.

We're also pretty constrained by this, as anyone who has wanted to set up a custom in-app login page, in-app user registry, or even server-level specialized user repository knows. The convenience comes with a cost.

Java EE's Routes

Authentication in Java EE has a complicated history, but the general idea is that there are three main current ways to handle user registries and authentication:

  1. Container authentication, which is roughly equivalent to Domino. In this case, you configure your server with knowledge about the user registry (say, a static set of users or an LDAP server) and how those users map to "roles" in the JEE sense (more on this in a bit), and then your app just tells the server what parts need login.
  2. Per-app custom authentication. This is roughly equivalent to doing a special in-app session cookie in a Domino app for authentication, but the hooks provided by Java EE make it easier to manage. You could do this entirely homebrew or use a project like Apache Shiro to do the heavy lifting for you.
  3. The Java EE Security API 1.0. This is a new standard, introduced in Java EE 8, meant to give apps the fine-grained custom control of the second option while offloading as many particulars as desired to the servlet container - essentially, a "best of both worlds" approach. In practice, I've found it a bit under-documented and fiddly in its current incarnation, but I'll aim to cover it in a future post.

Container Authentication

For this post, I'll cover setting up container authentication, since it's the easiest, is well-documented, and can even serve the "per-app" role if you follow the "one app per server" model that's in vogue for microservice/"cloud native" applications.

For testing and development cases, web servers generally provide a mechanism for writing out a simple user/password list. Open Liberty does this via server.xml and Tomcat/TomEE does it via tomcat-users.xml. However, since we're Domino people, that means we have access to an LDAP server we're already comfortable with running, so we can jump right into a "real" setup.

Configuring Domino for LDAP

This topic is a bit out of the bailiwick of this series, but usually it just means creating an LDAP Internet Site and running load ldap. Domino's pretty convenient sometimes. I like to test a freshly-configured LDAP server with Apache Directory Studio.

Configuring Liberty

Once you have LDAP running and working, open Liberty's "server.xml" file (dubbed "Server Configuration" in Eclipse's Servers view) and add the ldapRegistry-3.0 feature and an ldapRegistry element within the top-level server element, customized for your setup:

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

<ldapRegistry host="some.domino.server" port="389" sslEnabled="false"
    	bindDN="someuser" bindPassword="somepassword" 
    	ldapType="IBM Lotus Domino" baseDN=""/>

There are ways to prevent putting an unencrypted password in the "server.xml" file, but this will do for now.

As a nice bonus, Liberty's IBM provenance means we get built-in knowledge of Domino and so don't have to jump through the common hoops of setting up query filters and whatnot.

The other bit of configuration in this file is to map users and groups to roles. This is an area where Domino and JEE diverge a bit. "Roles" in JEE mean more or less the same thing as in Domino, but they're configured outside of the application. They can be configured per-app within the server configuration, accomplishing the same end result, but there's a different level of indirection. For our users, we'll configure them server-wide. So, add another element as a peer to the ldapRegistry:

<authorization-roles>
  <security-role name="admin">
    <group name="LocalDomainAdmins"/>
  </security-role>
</authorization-roles>

You can feel free to customize this at will - there's also a user type and the concept lines up pretty much with what you'd expect.

Configuring the App

The server configuration on its own doesn't yet change anything - we can still visit any page in the app without a login prompt. What we should do now is to clamp down certain aspects. To demonstrate this, we'll add a UI operation for deleting people and restrict it to our freshly-minted "admin" role. Go to the PersonController class and add the method:

@POST
@Path("{id}/delete")
@RolesAllowed("admin")
@Controller
@Operation(hidden=true)
public String deletePerson(@PathParam("id") String id) {
  personRepository.deleteById(id);
  return "redirect:people"; //$NON-NLS-1$
}

Note that we're using POST for this instead of DELETE as a nod to web browsers' historical limitations. There is a way to intercept and remap incoming requests so that we can use @DELETE annotations that I may cover later, but for now this should work fine.

Modify the "personList.tag" file within "WEB-INF/tags" in "Deployed Resources" to include a button to point to this action:

<%@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>
			<th></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>
		    	<td>
		    		<form action="${pageContext.request.contextPath}/resources/people/${person.id}/delete" method="POST">
		    			<input type="submit" value="X"/>
		    		</form>
		    	</td>
		    </tr>
		</c:forEach>
	</tbody>
</table>

If you visit http://localhost:9091/javaeetutorial/resources/people and click one of the deletion buttons, you should be greeted with an HTTP Basic authentication prompt that should block you until you enter in valid credentials for an admin.

Next Steps

At this point, we've really covered the main aspects that you'd need to know when making the move to Java EE. After this point, I have some ideas for various miscellaneous posts - other authentication options, app fit and finish, JSF, app configuration, deployment, and so forth - but, if you've been following along, I suggest you take the opportunity now to explore for yourself.

It would also be worth your time to look up some other existing educational resources. I hear that Java Brains is quite good on a lot of these topics, and Adam Bien is one of the leading sources for Java EE examples (and is the source of the template we used at the very start). When looking around, be wary of the age of the content: though pretty much anything related to Java EE will still work, there was a big move away from the Bad Old Days in recent versions, particularly EE 8, and so older examples may have you jump through uglier hoops than necessary. There are also whole technologies that are in common use that are not of immediate interest to us, such as Enterprise JavaBeans, so you can learn or not learn about those at will.

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

Sat Feb 16 12:49:13 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?

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

Fri Feb 15 12:48:50 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?

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="name" 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>Name</dt>
			<dd><c:out value="${person.name}"/></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 9: IDE Features Grab Bag

Wed Feb 13 11:50:26 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?

In today's post, I'm going to go over a handful of features that IDEs, particularly Eclipse, bring to the table to improve the development experience. Some of these aren't unique to EE development, but our use of Maven and standardized technology makes them better than their equivalents in XPages development.

Open Declaration

In Eclipse, if you right click on most anything in a Java file, you can choose "Open Declaration" (or press F3 with the text cursor inside it), you can go to the source of whatever it is, if available:

Open Declaration menu item

This also works in Designer, but it's often much more useful here: because Designer ships without source for its JVM or really any of the classes that make up the XPage stack, you tend to be greeted by the white "here's a bunch of bytecode" screen, which is rarely particularly useful.

Since we're working with open-source components and we told Eclipse to download source and Javadoc for Maven artifacts, though, almost everything will have available source, letting you explore what's happening much more easily.

This will also work for your own code, making F3 an extremely-useful method of navigation. While you're there, try out the "Open Type Hierarchy" and "Open Call Hierarchy" options too.

Open Implementation

CDI's technique of using @Inject to inject implementations of interfaces automatically is a great way to abstract away the business of doing a new SomethingImpl() or finding the managed bean. However, sometimes it's good to find out where the objects you're getting are actually coming from, and Eclipse lets you do this by holding Command (probably Control on Windows, if I had to guess) and hovering over an interface name:

Open Implementation menu option

In this menu, "Open Declaration" will take you to the Models interface class file, while "Open Implementation" will take you to the ModelsImpl implementation class.

Note, though, that Eclipse isn't really following CDI logic here - instead, it's just trying to find implementing classes and either opening a single implementation if there's only one or showing a menu to select from multiple. It happens that that's usually the same thing effectively, but it's an important distinction.

IntelliJ is a bit smarter on this point: it will try to figure out all the CDI logic and show a little bean icon on a line with an injection to take you to the object or method providing it:

IntelliJ bean detection

JBoss Tools

To be fair to Eclipse, there is a project to provide a great deal of improved Java EE behavior: JBoss Tools. It comes with a bunch of addins, editors, and configurators meant to make Eclipse much more aware of things like CDI's real logic. I personally have found it pretty janky in practice, but it's been a while since I gave it a proper shot. Your mileage may vary.

JAX-RS Resources

Since JAX-RS is such a critical part of modern Java development, it comes in handy that Eclipse has some specialized knowledge of it. If you expand the "Services" folder in your project, you'll have a "REST" folder that contains all of your declared JAX-RS endpoint classes and their methods:

Eclipse JAX-RS resource listing

You can use this as a general overview of your app's external API (and, when using MVC, its full URL layout) and you can also double-click any of the entries to go to the declaration.

If you get into a situation where you're writing a paired set of a server module and a client module, you can also let Eclipse generate a resource client class for you.

Deployment Descriptor

Within the "Deployment Descriptor" node in your project, Eclipse lists a bunch of EE/Servlet stuff:

Deployment Descriptor node

Historically, this referred specifically to the contents of the web.xml, but it also shows annotated classes as applicable - such as the Listener coming from the Ozark MVC implementation. Depending on how you're constructing your app, this may be more or less useful, but it's definitely good to know it's there.

Up Next

Next time, maybe I'll finally get to talking about users and data. Or maybe I won't! We'll see.

 

XPages to Java EE, Part 8: IDE Server Integration

Tue Feb 12 10:52:21 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 said that the next post was going to be about authentication or databases, but I'm turning that into a filthy lie. Instead, we're going to take a bit of a detour to talk about a couple ways to let the IDE help you out in development. I'll be talking about Eclipse specifically, but I know that at least the paid version of IntelliJ IDEA has similar features. The first feature on the docket is having the IDE manage an app server for you.

Servers

Up until this point, we've been using the TomEE Maven plugin to create and launch a server for us, which is convenient and portable across whatever environment you're working with. However, once you have a couple applications or want to make persistent server configurations outside of the individual app's pom.xml, it makes sense to run a server and deploy the app to it.

This is where Eclipse's "Servers" view comes into play. If the panel isn't currently in your workspace, go to Window -> Show View -> Other... and choose "Servers" under the "Server" category. By default, it'll be stacked with some other tabs, but I like to position this pane in the bottom-right of my IDE:

Eclipse Servers view

The way this view tends to work is that it points either at a local server installation or to a running remote server. We'll want the former, but, sadly, this is where we part ways with TomEE. Though the server is more than capable for our needs, the Eclipse integration (based on base Tomcat) is not, and it hinders its use here. Instead, we'll be switching to my current favorite: Open Liberty. Download the latest build from that page (19.0.0.1 as of this writing) and extract the archive to some location on your system (I like to keep a directory of various app servers).

Next, we'll need to install the Liberty support plugin in Eclipse, which is a fortunately-simple matter. Visit the Liberty in Eclipse download page and drag the "Install" button onto your Eclipse toolbar. Once it loads, click Next and Finish a couple times until it's done, and then let it restart Eclipse.

Once Eclipse restarts, click that "Click this link to create a new server..." link. In the resultant dialog, choose "Liberty Server" under the "IBM" category and give it a descriptive name:

Eclipse's New Server dialog

Click Next > and enter the path where you extracted Open Liberty in the "Path" field:

Server path

Click Next >, leave everything at its default, and click Finish.

Click the twistie next to the newly-created server and double-click the "Server Configuration [server.xml] new server" entry to open the server config editor. If it opens on the "Design" tab, click the "Source" tab to see the XML configuration. Set it to:

<server description="new server">
    <!-- Enable features -->
    <featureManager>
        <feature>javaee-8.0</feature>
        <feature>localConnector-1.0</feature>
    </featureManager>

    <!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
    <httpEndpoint httpPort="9091" httpsPort="9443" id="defaultHttpEndpoint"/>

    <!-- Automatically expand WAR files and EAR files -->
    <applicationManager autoExpand="true"/>
  
    <keyStore id="defaultKeyStore" password="testKeystore"/>
</server>

 

The first difference here from the default is to swap out the jsp-2.3 feature for javaee-8.0. Liberty organizes its capabilities by "features" in order to let you really trim down the runtime if you don't need specific capabilities. For our sake, we want the whole EE shebang available, though. localConnector-1.0 remains, and is what allows Eclipse to control the server.

We also changed the httpPort of the httpEndpoint element to 9091 to match what we've been using via the Maven config. We also added a basic not-exactly-secure keyStore configuration. This would be filled in more if you enable SSL.

Deploying the App

There are several ways to actually get our app onto this server, but the one I've built up a habit of using is to right-click the project, and then select Run As -> Run On Server:

Run on Server

The newly-created server should be selected by default in the resultant dialog, so just click Finish immediately.

The server will churn for a bit and eventually output [AUDIT ] CWWKT0016I: Web application available (default_host): http://localhost:9091/javaeetutorial/. It will also, I note with chagrin, output this:

[ERROR   ] SRVE0283E: Exception caught while initializing context: java.lang.IllegalArgumentException: The controller com.example.HomeController is not a managed CDI bean. Maybe the controller class is missing a scope annotation (e.g. @RequestScoped).
	at org.mvcspec.ozark.servlet.OzarkServletContextListener.failIfNoCdiBean(OzarkServletContextListener.java:76)
	at org.mvcspec.ozark.servlet.OzarkServletContextListener.contextInitialized(OzarkServletContextListener.java:60)
	at com.ibm.ws.webcontainer.webapp.WebApp.notifyServletContextCreated(WebApp.java:2377)
	at [internal classes]

That's because I forgot a step in the setup of MVC controllers yesterday, which is that you're supposed to add one of those annotations to the class too. Fortunately, the examples still work, and we'll fix that omission next time we edit the code.

Most likely, Eclipse will automatically open the app's default page in whatever browser it's configured to use - by default, a browser embedded in Eclipse itself.

Updating the App

In future posts, rather than specifically saying to run the clean install tomee:run Maven goal, I'll just say to run the app - either way should still work. By default, Eclipse will re-deploy the application to Liberty after changes, so you probably won't need to do anything other than refresh the page to see future changes.

Next Up

Next, I think I'm going to cover a grab bag of other features Eclipse has for working with Java EE apps before returning to the dirty business of writing code.

 

XPages to Java EE, Part 7: MVC

Mon Feb 11 15:04:22 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 last post that the rest of this tutorial is going to involve making some technology choices that are less universal than the ones up until this point. While pretty much every new EE app is going to involve CDI and JAX-RS, things will start to diverge once you decide on how you're going to handle authentication, your UI, and your data storage. We're going to dip into the the second one of those today.

Specifically, we'll be choosing the characteristically-dryly-named MVC Spec as the foundation for our interface.

MVC

If you're not familiar with the term "MVC" in a general sense, it stands for Model-View-Controller, and it represents one of the common ways to structure your application to keep the code clean and growable without it turning into a nightmare. There are other ways, and there are some flaws in the design that require band-aid solutions, but in general it remains a very-useful way to write your app. The general idea is that you have three components: the "model" (your data), the "view" (what your user sees), and the "controller" (what connects the two). On the web, this often takes the shape of having controllers pointed to by the "routing" within your application (e.g. /posts/new), which then do the work of fetching the data and binding it to the view.

XPages is ostensibly MVC-based, but that doesn't really play out in reality. The stack and IDE encourage direct mingling of the view and data (the <xp:dominoDocument/> data source and SSJS are the primary culprits here), and the lack of a model framework and the stultifying strictures of the built-in NHTTP routing make it very difficult to do it right even if you try (and lord knows we tried).

The MVC Spec

I've talked a bit about the spec before, and the idea of it is to build a simple-to-write-and-read MVC standard for Java EE, using existing EE technologies for the "view" part. I believe that the spec is heavily based on Spring MVC, though I haven't written any Spring apps.

The main reason I'm such a big fan of this spec is that it builds cleanly on top of JAX-RS, which already provides an excellent skeleton for cleanly-organized apps. JAX-RS already encourages clean, RESTful design for accessing data objects, and MVC builds on that to provide a natural way to display a web UI for non-API clients (which is to say, humans).

One thing to bear in mind with MVC 1.0 is that it's not quite a true Java EE component. It was slated for inclusion in Java EE 8, but Oracle cut it from the list before release. However, the spec has support within the Jakarta EE community and remains a likely candidate for future inclusion. Moreover, because the spec is so small and strongly encourages clean design, I feel that it's worth building upon - even if it disappeared tomorrow, almost all of your code would still work.

Adding to the Project

Since the spec isn't included in the default Java EE 8 spec or with EE servers, we'll need to add explicit dependencies to the pom.xml for the project, for both the spec itself and the reference implementation (currently named "Ozark", but it's going through a rename to "Krazo" for trademark purposes):

<!-- MVC 1.0 -->
<dependency>
  <groupId>javax.mvc</groupId>
  <artifactId>javax.mvc-api</artifactId>
  <version>1.0-pfd</version>
</dependency>
<dependency>
  <groupId>org.mvc-spec.ozark</groupId>
  <artifactId>ozark-core</artifactId>
  <version>1.0.0-m04</version>
</dependency>

Creating the Controller

MVC Controllers are implemented as normal JAX-RS resources with the extra @Controller annotation, and whose methods return an indicator of what view to use. Create a class in the com.example package called HomeController:

package com.example;

import java.time.LocalDateTime;

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

@Path("/")
@Controller
public class HomeController {
	@Inject
	Models models;
	
	@GET
	public String hello() {
		models.put("hello", "Hello, MVC!"); //$NON-NLS-1$
		models.put("now", LocalDateTime.now()); //$NON-NLS-1$
		
		return "hello.jsp"; //$NON-NLS-1$
	}
}

The "Models" object is a MVC-provided object that acts sort of like a viewScope: you toss whatever objects you'd like into it and they're available as variables on your page. Despite having an important-sounding name, it's really just a simplified Map.

Creating the View

MVC supports several "templating" technologies, among them JSP and JSF Facelets. However, though it uses JSF technology, it's not meant to be used for a full JSF app with server-side state. From what I can tell, the JSF support is more for those who already have JSF apps to use. Despite XPages's heritage, that doesn't really apply to us. Create a new folder named "views" within the "webapp/WEB-INF" directory in "Deployed Resources" (which is "src/main/webapp" in the filesystem). Then, create a new file and call it "hello.jsp":

hello.xhtml location

Set its contents to:

<%@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>
		<h1>${hello}</h1>
		<p>I was loaded at ${now}.</p>
	</body>
</html>

Since this still uses CDI, we're still able to use the translation bean we set up earlier, but now we have access to the extra variables the controller set up.

If you do another Maven build with goals "clean install tomee:run" and visit http://localhost:8081/javaeetutorial/resources now, you should be greeted with the expected basic page:

Basic MVC output

Working With a Model

So that's two out of three down; time to simulate some data access. Using a real backing database will be its own large topic, so for now we'll create a simple in-memory object.

Create a new class in the "com.example" package named "PersonController":

package com.example;

import javax.inject.Inject;
import javax.mvc.Controller;
import javax.mvc.Models;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.ws.rs.BeanParam;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;

@Path("/people")
@Controller
public class PersonController {
	public static class FormPerson {
		@FormParam("firstName") @NotEmpty
		private String firstName;
		@FormParam("lastName") @NotEmpty
		private String lastName;
		
		public String getFirstName() { return firstName; }
		public String getLastName() { return lastName; }
	}

	
	@Inject
	Models models;
	
	@GET
	public String home() {
		return "person-new.jsp"; //$NON-NLS-1$
	}
	
	@POST
	public String createPerson(@BeanParam @Valid FormPerson person) {
		models.put("person", person); //$NON-NLS-1$
		return "person-created.jsp"; //$NON-NLS-1$
	}
}

Next, create a new file in the "WEB-INF/views" directory named "person-new.jsp":

<%@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>
		<h1>Create Person</h1>
		<form method="post" action="people">
			<dl>
				<dt>First Name</dt>
				<dd><input name="firstName" required/></dd>
			</dl>
			<dl>
				<dt>Last Name</dt>
				<dd><input name="lastName"/></dd>
			</dl>
			<input type="submit" value="Submit"/>
		</form>
	</body>
</html>

Finally, create a second JSP file in the same directory named "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" %>
<!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>Last Name</dt>
			<dd><c:out value="${person.lastName}"/></dd>
		</dl>
	</body>
</html>

Now, do another Maven build and visit http://localhost:9091/javaeetutorial/resources/people:

Create Person page

In this screenshot, you can see that the "First Name" field got a red outline because it's marked as required and I entered and then deleted a first name value. Neat!

Anyway, fill in something for "First Name" but not "Last Name", and hit "Submit". You'll be greeted with... nothing! Well, visibly nothing, anyway. You'll have a 400 response in your browser with no content, and you'll see a line like this in your server console:

11-Feb-2019 14:52:55.942 WARNING [http-nio-9091-exec-2] org.apache.cxf.jaxrs.validation.ValidationExceptionMapper.toResponse Value '' of PersonController.createPerson.arg0.lastName: {javax.validation.constraints.NotEmpty.message}

Hey, the server-side validation worked! Down the line, we'll probably add an exception handler to display this type of thing to the user, but, for now, the important part is that invalid data was blocked before it even got to our code.

Go back and enter something for each of the name fields, and then hit "Submit" again. While doing so, bask in the pleasant fact that, because there's no server-side state, you don't need to worry about mangled JSF view state or anything. Once you submit, you should be greeted with the "Created Person" page with your data:

Created Person page

As a nice bonus, because this output page uses the JSTL <c:out/> tag, the values are nicely HTML-escaped, making it a bit more secure than our original Hello World page.

Next Steps

In the next couple posts, we'll cover the ominous topics of authentication and data storage.

XPages to Java EE, Part 6: Dependencies

Thu Jan 31 15:46: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?

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

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

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

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

Eclipse Prep

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

Eclipse's Maven preferences

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

Adding the Dependency

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

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

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

Eclipse's Maven Dependencies library

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

Using the Dependency

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

package com.example;

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

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

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

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

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

Markdown HTML output

Updating the Dependency

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

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

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

Next Steps

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

XPages to Java EE, Part 5: Web Pages

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.

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.