Posts tagged ‘annotation’

Introduction

After spending some time with Liferay and doing a bunch of portlets, I noticed that they share some common functionality which is just copy-pasted which is wrong.

I also knew that Liferay offers its Service system – a service is a combination of Interface and Util class that land into tomcat’s lib/ext folder backed up by implementation located in either portlet or an ext environment and some spring xml to wire them up.

A first approach suggested that this is going to be a piece of cake but unfortunately I got NPE 🙁

So I started looking through Liferay source code to find out how service-builder generated services fetch implementation from global spring context and expose it to the rest of portlets through Util class. It all seemed as easy as casting Object into given interface buf unfortunately wasn’t and I got ClassCastException (spring forums recognizes as not programming to interfaces…)

I was kind of stuck.

So maybe there was something special about classes generated by service-builder  which makes them accessible from non-owning-portlet.

Class loader proxy

The answer is yes and it’s called Class loader proxy – the architecture that grew from the need to allow inter-portlet communication across tomcat class loader. It transformed into somewhat complex architecture, that requires following steps:

  1. Create an interface
  2. Wrap your code in static calls using service-util
  3. Acesses your impl through spring bean context
  4. Wrap bean aquired from bean context in Class loader proxy.
  5. Store proxy inside local portlet context.
As you can see number of layers that need to be written for a single method call can cause a headache. Additionally  CLP uses MethodKey/MethodInvocation classes internally which makes it even more complicated.
Exposing a single method through all these layers seemed rather exaggerated task but this way I could focus on building all the layers by hand and finally see my implementation class called properly from different portlets.

APT generator for boilerplate

At this point I felt the need for some kind of code-generator that would free me from declaring all these service/clp layers by hand and I reminded myself that Java 5 offered a tool called APT. APT is annotation pre-processor used by JPA2 authors to create type-safe Criteria API (in java6 it’s part of javac compiler). Using it is as simple as placing annotaton on desired item, declare processor being used and your annotation is pre-processed during some phase before compilation and compiled – magic!

Generating Liferay-service code with APT

After this a big lengthy introduction I can finally say that in this post I’m going to concentrate on building LiferayService processor that will generate Liferay’s service boilerplate code, using java interface as starting point. I’m fully aware of the factthat Liferay’s service builder generates interface from implementation but for most people I spoke with, this is counter-intuitive so I’ll stick to contract-first approach.

Afterwards I’ll show you how to create sample ext-plugin project in order to test your new processor in action.

If you don’t have any experience in building annotation processor I recommend reading Jorge Hidalgo annotation series which starts from the very basics and finishes on writing simple annotation Processor.

Define annotation

As you can see the annoation is only preserved for compile-time, that’s all we need for annotation processor.

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface LiferayService {
	public String value() default "portalClassLoader";
	public String initMethod() default "afterPropertiesSet";
}

LiferayService.java

Define view – templates for generated code

Now following best-practices adviced by Jorge from the formentioned blog entry I decided to use velocity template engine as view. We’re going to need 2 templates LiferayClp/LiferayUtil.

Their task is not that complicated:

  • add package declaration
  • add class declaration – using original name + suffix (Clp/Util)
  • add declaration for all passed methods
  • add init-method declaration
  • add class loader fetch

Define model – pass pieces of information from processor to view

All the pieces of information required by view are contained in processor model:
	public final Name getClassName() {
		return get(KEY_CLASS_NAME);
	}

	public final Name getPackageName() {
		return get(KEY_PACKAGE_NAME);
	}

	public final String getClassLoader() {
		return get(KEY_CLASS_LOADER);
	}

	public final String getInitMethod() {
		return get(KEY_INIT_METHOD);
	}

	public final Map getMethods() {
		return get(KEY_METHODS);
	}

	public final Map getModelMap() {
		return Collections.unmodifiableMap(modelMap);
	}

	public String getQualifiedName() {
		return getPackageName() + "." + getClassName();
	}

	public Set getSuffixes() {
		return EnumSet.allOf(Suffix.class);
	}
The code above is just an excerpt to see the main interface, you can view whole model here.

Get list of methods that need to be proxied

So now we have to decide what methods are the right ones that we would like to use in our service. Using interface as an entry point makes it a little bit easier since we don’t need to distinguish between implementation methods and some utility methods – getMethods can just take all methods that are abstract and non-native:


	private Map getMethodsToProxy(TypeElement classElement) {
		Map methods = new HashMap();

		List members = processingEnv.getElementUtils().getAllMembers(classElement);

		UniqueNameSupplier uns = new UniqueNameSupplier();

		for (Element member : members) {
			if (isInterfaceMethod(member)) {
				String methodName = uns.supplyUniqueName(member.getSimpleName());
				methods.put(methodName, member);
			}
		}

		return methods;
	}

It uses UniqueNameSupplier class which might need some extra attention – CLP class contains list of fields that share their name with proxied method name. So for each interface method we have a method declaration and field declaration but there is no mechanism that mimics method overloads for fields, so we just need to make sure that field names are unique. The uniqueness of CLP field is achieved by giving field name the same name as method and in case there’s a potential name-clash appending a number that prevents it – not a very sofisticated name-mangling.

Combine it all together

In order to use it inside IDE like Eclipse it’s best to have a simple archive – that’s why I decided to use maven assembly plugin with a simple configuration that just filters out all META-INF directories in order to preserve processor service file.

Summary

Basically this is it – there are some other extension points that you might use but feel free to explore them on your own:)

Sources and binaries

Sources are available on github.
Binaries in my private repo.

In my next installment I’ll write some basic usage scenario with ext-pluign and sample portlet.

That’s it!

Problem description

Recently I joined a project that uses tapestry5 – a very nicely organized framework for web development with its own IoC mechanisms, great error reporting and very productive. And to me it still holds closest to its goal – it should be easy to edit templates by non-programmers.

Let’s get to the point – on one of pages I needed to display a dropdown, which is quite nicely described in tapestry documentation but to make things a little bit more compliated the model for the dropdown must be persistent throughout requests. At first it looked like a piece-of-cake, just add @Persist annotation to the model field and that’s it. Under jetty (which is our development environment) it all looked nice but after moving to Glassfish (which is production environment) strange error apeared, stating that SelectModel cannot be stored in session since it doesn’t implement Serializable interface.

So I asked our tapestry guru what’s going on and why can’t I store SelectModel in session and he said that Tapestry components should not be stored in session and the only thing that I should keep in session is the backing list for which model should be regenerated for each request.

This sounded awkward to me – because I envisioned all this repetitive code for converting Lists into SelectModels so they could be properly displayed.

I knew there had to be a better way…

Solution description

Fortunately tapestry gives you a very nice way of hooking into it’s bytecode manipulation mechanisms by implementing ComponentClassTransformWorker2 (available since v. 5.3), so I decided on a following solution:

  • each field that is supposed to be displayed as dropdown should be marked with some specialized annotation (say @SelectModel)
  • there should be some magical way of transforming a list into a SelectModel behind-the-scenes so view gets it with no other line of code.

I started googling and I found very similar case – there was a mixin, that should be added to every label. This post gave me an idea how to plug my bytecode manipulation service into tapestry plugin mechanism.

Usage

  1. As mentioned in solution plan the whole thing starts with annotating field with @SelectModel annotation, which requires name of field that should be used as option label.
  2. And you need to register SelectModelPropertyWorker in you AppModule.

And that’s it – now you can start using your list field as SelectModel in your view under the same name.

As you may have noticed SelectModelPropertyWorkier injects ServiceModelFactory under weird name so the getter can produce you model. If you know a better way to do it – just leave a comment and I’ll definitely include it.

Known limitations

There are 2 things that you need to keep in mind when working with @SelectModel annotation:

  1. The field cannot have @Property annotation since tapestry default mechanism will try to generate getter and setter which might give weird exceptions
  2. Since there cannot be getter so you cannot add it manually as well

Source code

Source code available on github.