Posts tagged ‘service’

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

Let’s say that your multi-tiered application consists of numerous components:

  • webservice server
  • webservice client
  • business component-logic
  • front-end web application

These components communicate with each-other through SOAP webservices and from time to time your customer is reporting an error which you know is caused by non-compatible changes done in the webservice call – which baiscally means that he did not do a full upgrade – one of the components is at least one version behind.

The project is built using maven and each release has its own version so the idea is to put this version into easily-accessible form so that each time this problem rises developers could ask customer for the version of a component and thus make sure that problem rised is not upgrade issue.

Requirements

So lets first specify requirements for this task:

I want to have version of each component easily accessible for users. Version should be applied automatically . After a release it should not be possible to alter version without recompiling the code.

Solution discussion

Version should be easily accessible

The first requirement is a little bit vauge easily accessible mitght differ from person to person but it’s also stated that person accessing it might have little or nothing to do with development or programming at all, that’s why solution with writing version of component into the log file might not be enough.

Probably the easiest solution is just to point user to a certain URL within application server, let him take screenshot of version and treat it as PREREQUISITE of all bug reports.

All application servers have managed beans and in JBoss there’s also a jmx-console where mbeans can be accessed with their properties and in case sombody still prefers command line – there’s a utility script called twiddle that can access mbeans from command-line. In order for this to work there needs to be mbean configured within JBoss application server.

Version should be applied automatically

Since project is built with maven this requirement is achieved easily – we just need to add resource filtering, apply version number within the resource and make it accessible to the mbean.

It should not be possible to alter version without recompiling the code

This requirement makes it a bit more compliated – using the previous one only, it could have been just a text file added to the jar and than loaded using Property class. Right now the only option is to have somehow java class treated as a resource, this means that first there should be resource filtering applied and java class should be placed in src/main/java and than everything would go as normal.

This makes any changes to this class a bit harder since one must know that version class is someplace else than src/main/java but proper comment should do the trick.

Solution description

Requirement analysis presented us with a view of how the solution should look like:

  • It should be a java class
  • This java class should be filtered using maven resource filtering
  • This java class should have version property applied when doing resource filtering
  • This java class should be treated by JBoss application server as mbean
  • mbean should contain a meaningful name so it’s easy to find it in the jmx console

Let’s start with creating a java class for our mbean:


public class MyVersion {

  private String version = "${project.version}";

  public String getVersion() {

    return version;

  }

}

As you can see in the code sample above, version property does have a setter – this is a way to mark it as readonly property in the JMX console.

Now maven needs to know that this class should be treated as regular resource and apply filtering – thus replacing project.version property with current version number.

So first approach would be to change src/man/java into something different but since it’s a strong convention this proved to be hard (if not impossible).

So another approach is to use special directory called src/main/tpl and add it as additional resource directory whose output should be placed into src/main/java.

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.5</version>
        <executions>
          <execution>
            <id>copy-resources</id>
            <!-- here the phase you need -->
            <phase>validate</phase>
            <goals>
              <goal>copy-resources</goal>
            </goals>
            <configuration>
              <outputDirectory>${basedir}/src/main/java</outputDirectory>
              <resources>
                <resource>
                  <directory>src/main/tpl</directory>
                  <filtering>true</filtering>
                  <includes>
                    <include>**/*.java</include>
                  </includes>
                </resource>
              </resources>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
    ...
  </build>
  ...
</project>

The only thing that’s left is to register our mbean so it’s available through JMX console. On JBoss there’s special extension of EJB3 specification called POJO service. It’s specific annotation that informes JBoss AS to create single instance of your class and have it registered in JNDI under specified name.

So let’s see how our code changes after applying it:

@Service(objectName = "projectName.VersionClass")
@Management(MyVersion.class)
public class MyVersionImpl implements MyVersion {

 private String version = "${project.version}";

 public String getVersion() {

 return version;

 }

}

As you can see in the code above – there are two annotations @Service and @Management. The latter requires a management interface to be specified so let’s create one:


public interface MyVersion {

String getVersion();

}

And that’s it – now we can always tell our client to first provide us with screenshot of a version before handling any bug reports.

NOTE:  In case you were wondering if it’s possible to add service mbean into existing jar in your project be warned that the author of this post has tried that and JBoss AS tried to register the same mbean twice – first when loading the jar alone and second time when loading the jar as a dependency of embedded war which as you can guess resulted in Exception thrown.

UPDATE: See updated version of this solution – using ejb 3.1 only, compilant with any application server here.