Charles Forsythe's Resume Charles Forsythe's Resume

You do not have the roles required to access this portlet.

My Technical Blog My Technical Blog

Liferay 6.1.1 (on Tomcat) Breaks Spring and Freemarker: Quick Fix Edition

I've been working with Liferay 6.1.0.  It's what I have deployed on my server and so it's what I develop against.  This week, I had to introduce some colleagues to the joys of Liferay development, so I had them "download the latest Liferay on Tomcat."  This turned out to be Liferay 6.1.1; when they deployed my demonstration portlet, it fell over. 

It was pretty clear that Freemarker integration was at the core of the problem, and after several days, I worked it out to a grim conclusion: Liferay 6.1.1 (on Tomcat, at least) just won't work out of the box with Spring's Freemarker view.  I managed to solve the problem with Liferay 6.1.0, Spring, and Freemarker, but that solution doesn't work on Liferay 6.1.1.

The Old Problem

The problem with 6.1.0 was that the FreeMarkerViewResolver in Spring was not getting loaded with the ServletContext it needed.  The solution was to add a ContextLoaderListener to the web.xml.  This would be alerted to the Servlet context coming up and inject the context as necessary.  This "fix" is what broke. 

The New Problem

You can try various different approaches, but they all end up in one kind of failure or another.  The portlet startup no longer works with the ContextLoaderListener. The Freemarker view system in Spring is absolutely dependent on having a ServletContext, so we are faced with the problem of bootstrapping it when Liferay isn't providing us with one (directly).

The Quick Fix

The quick fix is to subclass the FreeMarkerViewResolver to work with Liferay startup.  This subclass will add the following features:

  • Explicit injection of the FreemarkerConfigurer bean (this is just to make the linkage clear)
  • The FreemarkerView instances will be explicitly populated with a Configuration and a ServletContext
  • The ServletContext will be obtained from... where?

Even though this subclass cleans up the mess a little bit, we still need a ServletContext.  We do get a PortletContext, but the PortletContext interface doesn't provide a method to get an underlying ServletContext.  In fact, there is no requirement that a PortletContext even have and underlying ServletContext.

It turns out that Liferay's implementation of PortletContext provides a method to get the ServletContext.  All we need to do is implement Spring's PortletContextAware interface, and Spring will give us Liferay's PortletContextImpl. In case you are wondering, yes, implementing PortletContextAware works as expected.  So here's what we would expect to work:

@Override
public void setPortletContext(PortletContext context) {
    setServletContext(((PortletContextImpl)context).getServletContext());
}

And... fail.  I don't know about JBoss or other containers, but in Tomcat, this throws a NoClassDefFoundError.  Trying to put the class in the class path of the Portlet results in a confusing ClassCastException wherein the JVM complains about casing PortletContextImpl to PortletContextImpl.  Yes, they are exactly the same class in terms of package and class name, but they are loaded by completely different class loaders, so the JVM considers them completely different classes.

Classloader problems like this can be worked around, but I decided to just bypass the entire issue using reflection. Here is the code I used that worked:

@Override
public void setPortletContext(PortletContext context) {
    try {
        Method m = context.getClass().getDeclaredMethod("getServletContext");
        setServletContext((ServletContext)m.invoke(context));
    } catch (Exception e) {
        throw new UnsupportedOperationException("couldn't get servletcontext", e);
    }
}

This code doesn't worry about what particular class implements the PortletContext interface, but it assumes that this implementation provides an additional method called getServletContext that returns a ServletContext.

I've zipped up a test project that shows you the configuration as well as the extended FreeMarkerViewResolver.  You will need to build it with Maven if you want to try it live.

Download freemarker-spring-portlet.zip

Moving Forward

Liferay 6.1.1 uses Spring 3.0.6. The current Spring release is 3.2.1and the Freemarker View is still a Servlet-based hack.  I really, really like using Freemarker, so I want to solve this once and for all.  In pursuit of that, I'll probably generate a "Porlet-native" Spring view layer for Freemarker.  If I start with Spring components, I should be able to make it look similar to what Spring has now for Servlets.  The main problem will be that I will have to abandon getting a ServletContext. A ServletContext is not absolutely necessary to use Freemarker, but Spring's helper macros seem to require it.

Another technology that forces you to supply a ServletContext is Freemarker's JSP taglib compatibility. I will probably break that, at least in the first pass.  I don't like JSP and I don't like JSP taglibs.  The taglib capability is really nice for those migrating from legacy JSP.  In reality, there is nothing you can do with a JSP taglib that you can't as well -- or better -- with a macro or a custom Freemaker Model object.  People should port their legacy functionality to a Freemarker-based solution and send JSP off to a farm where it can run and play with all the other bad ideas in technology history (particularly JSF).

Portlets, Request Headers and Liferay

It's been 5 weeks or so since I've posted.  I've been working on some side-projects (details to come!) and a server migration.  In the meantime, I came across another "problem with portable portlets."

As I mentioned previously, the Portlet API simply does not provide enough functionality to write a really complicated application.  Here is another thing that missing: a standard way of getting HTTP request headers. 

You might wonder why that would be difficult, but consider how Portlets differ from Servlets.  Portlets don't own the page, just a part of it.  Therefore, they don't own the HTTP request that invokes them. HTTP headers are for the Portlet container to look at, if anything, right?  That is certainly a solid argument for action and render URLs, but what about resource URLs? 

Resource URLs are used for AJAX requests, or when a request needs to download a document of some kind.  In these cases, the request wants only the data provided by the Portlet and no additional scaffolding from the container.  JSR-168 didn't have a way to do this, so resource URLs were added to address the problem in JSR-286.  While this was a great step forward, it failed to provide a way to get request headers.

One way that a container can deliver HTTP request headers, is by attaching them to the Portlet request as attributes.  Unfortunately, there's no mandate to do this, so the request header you want may not be included.  If you are using Liferay, you can cast the Portlet request to a proprietary interface class that allows access to the underlying Servlet request.  From there, you can get the request header.  Here is an example, where portletRequest is your original Portlet request instance:

((com.liferay.portal.kernel.portlet.LiferayPortletRequest) portletRequest).getHttpServletRequest().getHeader("SOAPAction");

By doing this, you would be making your code Liferay-specific.  As I said before, this is probably something you can't avoid.  In my previous post, I discuss some platform-dependence-mitigation strategies, if you really want to make your Portlets "portable."

The Know-It-All Guide to java.lang.String

You would think that after a few years, Java programmers would all know how to manage Java's most popular object: String.

If you work day-to-day with Java code, you see basic mistakes in code written recently by people with years of experience.  Here's a popular (but stupid) way to convert int to String:

    String s = intValue + "";

How about String composition code that generates so much heap clutter that the garbage collector threatens a strike? 

This is a cry for help, my friends, and help has arrived.  I've published The Know-It-All Guide to java.lang.String.  It's a thorough exploration of everything one should know about this object class.  If you know someone who has been writing atrocious Java code  for years -- someone who can't write "Hello, World!" without having Eclipse auto-generate most of the code -- then you know someone who ought to read this.

Of course, you don't need to read this.  Heck, you could have written this yourself.  Perhaps, though, you'll enjoy laughing at all of the obvious things I choose to point out, and wonder who the poor souls are who don't already know these things.

Also, It's free.

 

Deprogramming the Cargo Cult

Most people know that this is "the right way" to compare a String instance to a String literal:

    "value".equals(str)

If you do this:

    str.equals(value)

...someone will invariably tell you that you are doing it wrong.  That is usually true, but what if str, in this case, should never be null?  The answer is "well, just in case then."  In case of what?  If a value should never be null, then the code should throw a NullPointerException if it is null.  That what NullPointerException for.  A lot of people seem to think that NullPointerException means "this code forgot to handle null values."  No, it means, "this code doesn't accept null values, and you passed it one anyway."  The null value is handled: an exception was thrown.

The second version of the compare is perfectly fine if there is an assumption that str is not null.  Java provides a really great way to document/enforce this assumption:

    assert str != null;
    str.equals(value)

APIs, particularly when declared in interfaces, should specify whether or not null values are accepted.  There is nothing wrong with saying, "if parameter X is null, the method will throw a NullPointerException."

This is what happens when design becomes dogma: people do the "right thing" for the wrong reasons (because someone told them to do it that way), and they stop making sensible design decisions.  This was driven home when I encountered something like this in some legacy code:

    // if ("prefix".startsWith(text)) {
    if (text.startsWith("prefix")) {

What happened here? The coder needed to see if text started with "prefix" and knew to use the startsWith method.  He was so conditioned to using the String literal as the basis of comparison that he had stopped thinking about it, and coded it backwards at first.  Then, during debugging, he thought, "Wait, that might be backwards," and tried it the other way around.  It worked, but he never went back and erased the original attempt.  This left a history of Cargo Cult software design.

How do we get rid of stuff like this?  One obvious approach is training.  When programmers are left to train themselves, they will adopt approaches that they get from other programmers or examples on web sites.  It is no surprise that many times these self-directed research efforts result in the acquisition of outdated or blinkered approaches to solving technical problems.  It's like telling your kids to teach themselves about sex; would you be surprised that they end up contracting numerous STDs?

Another obvious approach is for technical leaders to keep up with new and better ways of doing things and to pass that along to their teams.  That is probably the most common plan in the corporate world, but it has a huge flaw: a lot of technical leaders are imbeciles.  Indeed, many technical leaders become managers because they are aren't particularly good at programming. Most of the awful coding practices I've encountered were "how we were told to do it at my last job," and those edicts came from the people whose job it is to know better.

One colleague told me about how she solved a particular problem using an elegant approach that involved inheritance.  Unfortunately, her solution was rejected because her classes were not EJBs.  There was no need for them to be accessed using RPCs, but her technical leadership had decided that it was going all-in on the EJB technology, so every object needed to be an EJB.  People higher up on the org chart had attached official-sounding terms like "architecture" to this ridiculous idea, so failing to follow it was deemed as "not adding value." Thus, her good idea was sacrificed in service of a bad idea.  I wonder how many developers left that organization with the belief that "the best systems is one where every object is an EJB."

The final suggestion for fixing this problem is usually "better process."  That's another one that's great in theory, but usually means "by calling our 2-hour status meeting 'scrums' we will be agile."

Java API Bloat, or Just More of it to Love?

I found a copy of the Java 1.0 API still hosted on someone's personal student web site.  According to the HTTP response header, it was posted there in October of 1995.

Java 1.0 had 8 "java" packages and 143 classes. I'm omitting a special "debug" package because that really didn't stick around long. About 20% of the API was dedicate to the world's worst GUI API: Java AWT.

By running src.zip through some filters, I count that Java 7 has 185 API packages containing 2987 top-level classes.  When you add inner classes, there are certainly over 3000 total classes.  This is after the Java Media Framework was removed from the core API.

The JMF was spun off in Java 6 because it carried with it a large binary signature (5Mb, I believe) and wasn't widely used.  In my opinion, there are a lot of APIs that could be uncoupled from the core APIs, starting with all the CORBA stuff.  I know that there are probably hundreds of systems where new Java code is integrating with an existing CORBA infrastructure, but does it really need to be in the core API?  I think that in the balance, the answer is: we put it there and it doesn't cost that much to keep it there.

I think that there is a lot of stuff in the core API that people should be aware of, and I plan to write some blog posts about them.  There is a lot of stuff, for example, for XML and XML-to-Object binding that people ought to know about.  For example, Java 5 internalized Xerces, so there's never any reason to include it in a project anymore, yet I see that people do (and code in explicit dependencies on it).  It's nice that you can plug in different XML processors, but if you like what you get from Xerces, it's been built in to the core platform since 2005.

Showing 1 - 5 of 16 results.
Items per Page 5
of 4

Hello World Hello World

Welcome to Liferay Portal Community Edition 6.1.0 CE (Paton / Build 6100 / January 6, 2012).

Publications Publications

Instant FreeMarker Starter

Instant Freemarker StarterThe Instance Freemarker Starter offers a quick introduction to using Freemarker in Enterprise projects. All of the key features of Freemarker Template Language (FTL) are covered with realistic examples. Also covered are integration with MVC frameworks such as Spring.

 

The Know-it-All Guide to java.langString

This guide provides a detailed description of how to work with Java's most-common class.  This included issues affecting memory usage, internationalization (i18n) and character encoding.

Second Edition: Now updated for Java 8!

(This has been taken offline for further edits)