Recent Changes - Search:


SourceForge Logo









YourKit Java Profiler

WritingFacets

Writing and assigning facets to their (name, profile, targetType) key is really easy. 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-line 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 (see below). The JFacets distribution contains a few Spring 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).

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.

Annotated classes are looked up from the CLASSPATH. You have to provide at least one base package (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.

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.

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.

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 April 11, 2009, at 11:21 PM