Recent Changes - Search:


SourceForge Logo









YourKit Java Profiler

WritingFacets

Writing and assigning facets to their (name, profile, targetType) key is as easy as invoking them. Generally speaking, you simply have to write a POJO (that possibly extends some interfaces, like IFacet, IInstanceFacet, etc., or even your own interfaces), and then specify the assignation key for this facet.

Here under is an example facet that uses the @FacetKey annotation in order to define the assignation key (explained below) :

@FacetKey(name="purchase", profileId="role_customer", targetObjectType=MyProduct.class)
public class MyFacet implements IFacet {

  private IFacetContext context;

  public IFacetContext getContext() {
    return context;
  }

  public void setContext(IFacetContext context) {
    this.context = context;
  }

  public void purchase() {
    MyProduct p = (MyProduct)context.getTargetObject();
    p.setPurchaseDate(new Date());
    ...
  }

}

As you can see, it's really no big deal : a POJO, and a one-liner annotation... could hardly be simpler !

Several other options are available for writing and assigning facets. You are not tied to annotations if you don't like them, and even more, you aren't even tied to writing your facets in Java !! JFacets uses pluggable Facet Descriptor Managers (FDM) and Facet Factories (FF), assembled via Spring, which allows you to implement virtually any facet definition mechanism (see the Architecture docs for more infos).

A few implementations are bundled with the JFacets core, which you can benefit directly by just hooking them in via Spring. The JFacets distribution contains a few XML application contexts that can be used for inspiration (look into the test resources)... Also, for a more involved example, you can have a look at Woko, which has a pretty cool implementation, where facets are Groovy code stored into the database !

Currently supported...

The included FDMs and FFs support the following ways of writing/assigning facets :

  • XML facet descriptor / Java Classes
  • Automatic facet discovery / Annotated Java Classes
  • Automatic facet discovery / Groovy Scripts & Classes

Each of the different options have pros and cons, but choice is always a good thing... You can use either only one "mode" or mix them in the same application, and of course, this does not have any impact on the way you use facets.

XML facet descriptor / Java Classes

In this "mode", you write the facets in pure Java (or in Groovy, but then you have to compile your Groovy code into .class files), as POJOs that can implement some of the JFacets interfaces. Then you assign the facets to the (name, profile, targetObjectType) key in an external XML Facets Descriptor file. This file is parsed at initialization in order to load the Facet Descriptors to be used for the lifetime of the application.

Here under is some code showing the definition of our example facet in the XML file :

<facets>
 <facet name="purchase" profile="role_customer" object_type="com.xyz.model.MyProduct" class="com.xyz.facets.MyFacet"/>
 <!-- some other facets here... -->
</facets>

As you can see, the facet's name, profileId and targetObjectType are specified as the name, profile and object_type attribubtes of the <facet> XML element, as well as its implementation class (class attribute of the <facet> element).

The path to the XML facets descriptors file is specified via Spring as a property of the Facet Descriptor Manager.

Pros And Cons

What's cool :

  • this is clean separation of concerns : facet implementation (how) and assignation (what, who) are well distinct, and in some cases mixing them may not be the best idea (e.g. reuse of existing facet classes, or even reuse of existing compiled code or library classes, like facetizing Swing components)
  • the XML file is a central place where you see all facets definitions

What sucks :

  • external config sometimes sucks in itself ! When you write a facet using this mode, you have to switch to your XML config and add a new entry in there...

Using annotations

This mode leverages Java annotations and auto discovery. You write facets in Java just like when you use the XML descriptor mode, but this time don't have to maintain an XML file. It's a tendency these days to have those auto discovery features, and it's very handy in some situations.

This mode uses another Facet Descriptor Manager which is configured in the Spring context, just like the other modes. You can use the annotations with or without other facet descriptor managers, it's just about geting it configured.

Annotated classes are looked up from the CLASSPATH. You have to provide at least one base package in the facet descriptor manager's Spring bean definition (look to the javadocs for more infos).

The @FacetKey annotation

Defining a facet using @FacetKey the annotation is really easy, as you've seen in our initial example. You somply have to annotate your class

@FacetKey(name="purchase", profileId="role_customer", targetObjectType=MyProduct.class)
public class MyFacet ... {
 ...
}

As you can see, the FacetKey annotation allows to specify :

  • the name of the facet ;
  • the ID of the profile ;
  • the facet's target object type.

And that's all !

NOTE
There is also a @FacetKeyList annotation that takes a list of @FacetKeys, in case you need to assign your facet class to multiple keys.

Pros And Cons

What's cool :

  • No external configuration : auto-discovery does the work for you ;

What sucks :

  • Facet assignation is now bound to the implementation, which breaks separation of concern (but at least it's pragmatic !)
  • Information is disseminated here and there, so facet assignation is harder to refactor

Facet discovery / Groovy Classes and Scripts

This mode provides full support for writing your facets in Groovy as facet Classes or as plain scripts ! Moreover, it also uses auto-discovery in order to find your facets and theis assignations without any external configuration required.

Automatic Facet Discovery and Assignation

Facets that you write in Groovy have to be available as CLASSPATH resources. At startup, the JFacets Groovy FDM scans the CLASSPATH in order to find some resources with the following naming convention :

 / basePackage / profileId / targetObjectType / name.facet (or .groovy)

  • basePackage : a base package name (e.g. com.xyz.app.facets), which is translated to a path ;
  • profileId : a folder named with the ID of the profile (e.g. role_customer) ;
  • targetObjectType : a folder with the target object type's fully qualified class name (e.g. com.xyz.app.model.MyProduct) ;
  • name : the name of the facet (e.g. doSomething) ;

The base package is not important : it's only an utility in order to put your facet scripts where you want to. This can be configured in the Spring context, depending on your application.

What's important is :

  • the order of the folders (has to be this one)
  • the .groovy or .facet file name and suffix

Here under are a few examples of valid Groovy facet files (once again, they have to be available as CLASSPATH resources), and their translated (name, profile, targetObjectType) key :

  • /com/xyz/app/facets/customer/com.xyz.app.model.MyProduct/purchase.groovy : (purchase, role_customer, MyProduct)
  • /groovy-facets/guest/java.util.List/sort.facet : (sort, guest, java.util.List)
  • /groovy-facets/admin/java.util.List/sort.facet : (sort, admin, java.util.List)
  • /x/y/z/UserManager/x.y.z.AppUser/update.groovy : (update, UserManager, x.y.z.AppUser)

As you can see, facet assignation follows the convention over configuration paradigm : the information is specified by the file/folders structure itself, instead of being duplicated in the XML file. You don't have to add anything to the file when using Groovy facets, you simply have to put it at the right place !

NOTE
You can specify base packages in the Spring config in order to avoid scanning the whole CLASSPATH at startup.

Groovy Classes or Executable Scripts

When writing Groovy facets, you have two options :

  • Define a class in your .groovy/.facet file ;
  • Write a plain script, with no definitions.

Groovy Classes

Defining the facet class in the Groovy file is strictly equivalent to coding the facet in Java. You simply declare write the class the Java way or the Groovy way, the choice is yours.

Here below is our "purchase" example in Groovy, located in file .../role_customer/com.xyz.app.model.MyProduct/purchase.groovy :

/**
 * A Groovy facet class
 */

class MyGroovyFacet implements IFacet {

  // GroovyBeans generates the contract of IFacet
  IFacetContext context


  void purchase() {
    // we do stuff with the target object
    // using a superclass method
    def product = ctx.targetObject
    product.purchaseDate = new Date()
    ...
  }

}

As you can see, the facet file simply defines the facet implementation class, the one that will get instanciated at run time when facets are looked up.

Another feature of Groovy Facets is the ability to to implement facets as plain scripts instead of classes...

Plain Scripts

You can also write your facets as plain scripts, with no class declaration. If you do so, the facet is automatically considered as executable, and thereby script is executed when you execute the facet. The FacetContext is available as a variable, and the script can return a value that becomes the result of the facet's execution.

Here under is an example of such a Plain Script Groovy Facet :

/*
 * plain script facet that increments and return an Integer
 * passed as the facet's target object
 */

i = context.targetObject;
i = new Integer(i.intValue() + 1);
return i;

NOTE
Of course, Plain Scripts are useful only with executable facets. It's something about scripts in general : you execute them :-)

Pros And Cons

What's cool :

  • No external configuration : auto-discovery does the work for you
  • You instantly benefit of Groovy's dynamic features and neat syntax to write your facets (it's damn flexible, fast and agile !)

What sucks :

  • Groovy facets (in the currrent implementation) are slower than pure Java ones

Edit - History - Print - Recent Changes - Search
Page last modified on October 05, 2007, at 10:01 PM