What To Do With All This XSP Markup?

Mar 29, 2021, 6:51 PM

Tags: xpages

In some previous posts, I've started talking about some steps one can take to make a complicated XPages app more platform-independent. There's a lot to be done there, refactoring code to bridge differences between runtime environments and to lessen dependencies on XPages-specifics things, but there's a huge elephant in the room: all that XSP markup.

Even if you have a cleanly-structured application where all of your logic is in Java and all of that code doesn't make expectations about the UI, there's still bound to be a big pile of XPages XML markup around, and that's not going anywhere. That's the best case, too: most XPages apps, even Java-based ones, are riddled with all sorts of expectations about the UI, from FacesContext to ExtLibUtil to the DominoDocument model layer.

This is a sticky problem, made all the moreso by the fact that, although XPages is a fork of JSF underneath, the XSP layer is its own special language and isn't really how stock JSF pages were ever written.

There's no really-great answer, but I've never been one to shy away from writing a list of possibilities. These range from actual things one can do right now to hypothetical speculation about what one could build to deal with it. This all starts from the assumption that you want to do something to lessen or remove your XPages dependency. You can instead choose, I suppose, to keep chugging along with it.

Practical Steps

Throw It All Out

This scenario is pretty straightforward: dump your XPages code and never look back. While this could take the form of dumping the stack entirely, I think in practice it will generally take the form of first refactoring your logic (if you haven't already) and then exposing it with REST services. Then, you let your XPages app chug along as-is while you build a new app in whatever else you want, and then swap over when your new app is complete enough.

Throw It All Out, But Slowly

This is similar to above, but you rebuild your app piecemeal, either in place or by sending users to a different app for some parts. This is a very-practical route for large, sprawling applications, and it's what we're doing with one of my clients.

The way it's specifically taking form there is that, when it comes time to write a new module or rewrite an existing one, we build that individual component as an Angular app using REST services and served from an OSGi bundle, and then host it in an <iframe> inside the XPage. So the app continues on as it is, but every once in a while a big chunk of it is deleted and replaced. The use of an <iframe> means that the JS app doesn't have to worry about clashes with the surrounding JavaScript libraries included on the XPage, but gets to share the authentication session. Over time, the XPages app will become essentially a master of ceremonies for the individual modules, and then one day we'll probably swap out that shell too.

Run It In A Webapp

This is a path that would really best be combined with something else, and, admittedly, is essentially specific to me personally. In this case, you use the xpages-runtime project to run your XPages inside a normal WAR container on a good server, and then use that as your base of operations for rebuilding.

My instinct with this project is always to say "well, it's really just an experimental thing", but I use it as my primary means of XPages development and as part of my client's CI chain to host testing builds deployed by Jenkins. There are some minor down sides involved in that you have to really know the innards of the stack inside and out if something goes wrong, and it's also absolutely unsupported by anyone. So... your mileage may vary.

That all said, it makes transforming your XPages app into a modern Java app a dream. You get the full Maven experience for dependencies, and you can use newer technologies without the hassle inherent in trying to cram them onto Domino. And, practicality-wise, it'd really just take a small amount of "abetted but not supported" tweaks on HCL's side to make it less me-specific.

Hypothetical Projects

These hypothetical approaches are naturally on a much-larger scale, and aren't really the sort of thing that one would do to solve their dilemma for an individual project. Really, they'd be HCL-led product decisions, and I'm spitballing even more than usual here.

Transform It To JSF

So I mentioned earlier that JSF markup isn't the same as XSP. The immediate difference between the two is the starting conceit: where an XPage is a fully-composed entity starting at xp:view, JSF syntax evolved from JSP and takes an "embedded in XHTML" approach, like this "hello world":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"      
      xmlns:h="http://java.sun.com/jsf/html">
    
    <h:head>
        <title>JSF 2.0 Hello World</title>
    </h:head>
    <h:body>
    	<h2>JSF 2.0 Hello World Example - hello.xhtml</h2>
    	<h:form>
    	   <h:inputText value="#{helloBean.name}"></h:inputText>
    	   <h:commandButton value="Welcome Me" action="welcome"></h:commandButton>
    	</h:form>
    </h:body>
</html>

If you're starting from an equivalent XPage, it wouldn't be too difficult to get here, and you might even be able to do it with XSLT. Take the xp:view pageTitle and move it to the <title> element, swap out xp:inputText for h:inputText, and so forth, and you're good to go.

That is... not what your average XPage looks like, though, and it doesn't take long for the notion of a clean transformation to crash and burn. SSJS aside, there are all sorts of gotchas: themes, custom controls, xp:eventHandler, any component outside of the core, on-page data sources, and so forth. You'd constantly hit things that are either too different in JSF or don't have equivalents at all.

Though I'm not a JSF master, I expect that it'd be essentially impractical to transform the source fully in this way. That said, you could use it as a starting point: auto-convert what you can and leave commented-out versions of the rest as TODOs for the developer.

Write A Driver For JSF

The other route would be to essentially re-implement XSP on top of JSF. All the XSP is there to do is to describe the XPage as a tree of components, and something could certainly interpret the XML into components slightly more easily than a source translation.

Still, though, this would essentially be equivalent in effort to the "update JSF" requests that the community has been making for years. That's easy to say, but much harder to actually do. Additionally, it'd be more implementation work than the above: while components like h:inputText and xp:inputText share a common ancestor, they're not perfectly compatible, and so there'd have to be a parallel component tree in the JSF runtime.

A Mix of Both

By this, I mean that you could take the "transform the XML to normal JSF" approach as above, converting compatible components over to their stock equivalents, but then re-basing the truly-XPages-specific parts into jakarta.faces classes and including them as a component package so that they'd coexist. This is essentially the "dominoFaces" idea.

While I'm skeptical of the value that this would provide to the larger world, it would be a practical hybrid approach, limiting the amount of code that would break to the stuff that really gets into the weeds of XPages-specific assumptions.

And maybe this is how I'd do it if I was tasked with the job. This would run into more-explicable edge cases than trying to transform the source and wouldn't implicitly encourage writing more pure XSP markup like the second option would.

Transform It To Something Else

Of course, JSF isn't the only game in town, so one could hypothetically try to convert these apps to something else entirely. I'm a little skeptical of the options here, admittedly. An approach that would try to split it to be more client-side than XPages is now would essentially require running the stack on the server anyway to handle all the server-side bindings, so I'm not sure what you'd gain. Moving it to a non-JSF server-side framework would avoid some of that trouble, but I'm not sure what you'd gain that would be worth the nightmare of edge cases.

Still, I want to give the option a mention, since it wouldn't be impossible to do something very clever and functional in this way. I just have my doubts about how worth it it would be. In my mind, moving back to mainline JSF on a good app container would be simpler to do while also leaving the door fully open for working with other tools alongside it much more easily than Domino has offered to date.

The Rest of the Work

This is all musing about the task of dealing with XSP markup specifically, and presupposes that you're willing to at least rewrite a bunch of logic as REST services or (more enjoyably) move to a non-Domino app server. While I have my various projects to make this sort of thing easier, I recognize that (for some reason) there's a big difference between "Jesse said this is possible" and "my company is investing heavily into doing this". Just getting a viable, supportable deployment environment that isn't another dead end would be a project of its own.

One big chunk of the work outside of the XSP markup itself and its relation to JSF is the way that "XPages" as such really represents a whole application stack, not just a UI framework. While there is a slice of it that remains essentially a distinct UI kit, there's a tremendous amount of stuff that lives nebulously in the realm between a root web server and the application framework. The HttpService stuff that I've talked about recently is one such part, sitting below the "web container" portion but being (at this point) an XPages-specific thing. Not all of that would need to come along for the ride, but some of it would, or at least some apps would have to account for it going missing.

Anyway, it's admittedly all a big ball of wax, and no option is really perfect. Still, I think it's important to consider and, ideally, execute on something.

New Comment