| Andrew Cooke | Contents | Latest | RSS | Twitter | Previous | Next

C[omp]ute

Welcome to my blog, which was once a mailing list of the same name and is still generated by mail. Please reply via the "comment" links.

Always interested in offers/projects/new ideas. Eclectic experience in fields like: numerical computing; Python web; Java enterprise; functional languages; GPGPU; SQL databases; etc. Based in Santiago, Chile; telecommute worldwide. CV; email.

Personal Projects

Lepl parser for Python.

Colorless Green.

Photography around Santiago.

SVG experiment.

Professional Portfolio

Calibration of seismometers.

Data access via web services.

Cache rewrite.

Extending OpenSSH.

Last 100 entries

Sentidos Comunes (Chilean Online Magazine); Hilary Mantel: The Assassination of Margaret Thatcher - August 6th 1983; NSA Interceptng Gmail During Delivery; General IIR Filters; What's happening with Scala?; Interesting (But Largely Illegible) Typeface; Retiring Essentialism; Poorest in UK, Poorest in N Europe; I Want To Be A Redneck!; Reverse Racism; The Lost Art Of Nomography; IBM Data Center (Photo); Interesting Account Of Gamma Hack; The Most Interesting Audiophile In The World; How did the first world war actually end?; Ky - Restaurant Santiago; The Black Dork Lives!; The UN Requires Unaninmous Decisions; LPIR - Steganography in Practice; How I Am 6; Clear Explanation of Verizon / Level 3 / Netflix; Teenage Girls; Formalising NSA Attacks; Switching Brakes (Tektro Hydraulic); Naim NAP 100 (Power Amp); AKG 550 First Impressions; Facebook manipulates emotions (no really); Map Reduce "No Longer Used" At Google; Removing RAID metadata; New Bike (Good Bike Shop, Santiago Chile); Removing APE Tags in Linux; Compiling Python 3.0 With GCC 4.8; Maven is Amazing; Generating Docs from a GitHub Wiki; Modular Shelves; Bash Best Practices; Good Emergency Gasfiter (Santiago, Chile); Readings in Recent Architecture; Roger Casement; Integrated Information Theory (Or Not); Possibly undefined macro AC_ENABLE_SHARED; Update on Charges; Sunburst Visualisation; Spectral Embeddings (Distances -> Coordinates); Introduction to Causality; Filtering To Help Colour-Blindness; ASUS 1015E-DS02 Too; Ready Player One; Writing Clear, Fast Julia Code; List of LatAm Novels; Running (for women); Building a Jenkins Plugin and a Jar (for Command Line use); Headphone Test Recordings; Causal Consistency; The Quest for Randomness; Chat Wars; Real-life Financial Co Without ACID Database...; Flexible Muscle-Based Locomotion for Bipedal Creatures; SQL Performance Explained; The Little Manual of API Design; Multiple Word Sizes; CRC - Next Steps; FizzBuzz; Update on CRCs; Decent Links / Discussion Community; Automated Reasoning About LLVM Optimizations and Undefined Behavior; A Painless Guide To CRC Error Detection Algorithms; Tests in Julia; Dave Eggers: what's so funny about peace, love and Starship?; Cello - High Level C Programming; autoreconf needs tar; Will Self Goes To Heathrow; Top 5 BioInformatics Papers; Vasovagal Response; Good Food in Vina; Chilean Drug Criminals Use Subsitution Cipher; Adrenaline; Stiglitz on the Impact of Technology; Why Not; How I Am 5; Lenovo X240 OpenSuse 13.1; NSA and GCHQ - Psychological Trolls; Finite Fields in Julia (Defining Your Own Number Type); Julian Assange; Starting Qemu on OpenSuse; Noisy GAs/TMs; Venezuela; Reinstalling GRUB with EFI; Instructions For Disabling KDE Indexing; Evolving Speakers; Changing Salt Size in Simple Crypt 3.0.0; Logarithmic Map (Moved); More Info; Words Found in Voynich Manuscript; An Inventory Of 3D Space-Filling Curves; Foxes Using Magnetic Fields To Hunt; 5 Rounds RC5 No Rotation; JP Morgan and Madoff; Ori - Secure, Distributed File System; Physical Unclonable Functions (PUFs); Prejudice on Reddit

© 2006-2013 Andrew Cooke (site) / post authors (content).

Static Mixins at the Presentation Layer with AspectJ and JSP

From: "andrew cooke" <andrew@...>

Date: Fri, 2 Dec 2005 09:38:27 -0300 (CLST)

A quick note on an interesting pattern I stumbled across yesterday.
It's very obvious in retrospect, but I think it's also an interesting
illustration of AspectJ in use, showing both its good and bad
features.


Background, Database Layer
--------------------------

I have some information in my database that I want to display in the
user's browser (don't we all?).  These are three integers - labelled
red, yellow and green - that "score" someone's performance (green is
good, red bad and yellow intermediate).

So I have a transport object - a bean - that is a transparent carrier
of this information (and other related values).  The database layer
supports reading and writing instances of this object.

This transport bean is very simple - a collection of private fields
with public setters/getters (largely auto-generated by Eclipse) that
provide dynamic access to the fields via introspection (what a bean
is, really).

Presentation Layer
------------------

At the presentation layer (inside a JSP tag) I decided to display the
information as an LED bar display (like you see on cheesy hi-fi).
However, the numeric values of these scores can be large, so I decided
to make the number of bars proportional to the log of the value (more
exactly; 1 + log2(n)).

Within the tag I would like to access these logarithmic values using
JSP's expression language.  So my tag code looks something like:

<c:if test="${value.red > 0}">
  <c:forEach begin="1" end="${value.logRed}">
    <img src="<c:url value="/themes/red.png"/>" alt="-" title="bad" />
  </c:forEach>
</c:if>

To do this, I need a getLogRed() getter on my object.  But my
transport bean only has a getRed() method.

Mixin
-----

Enter AspectJ.  In the part of my source tree related to presentation
I define an AspectJ mixin that adds the lgoarithm calculations.  This
is done in three steps.

First, I define an interface that provides the new functionality (I'll
only include red here, but in practice all three colours are present):

public interface LogColour {
  public int getLogRed();
}

Second, I add that interface to the transport bean, along with a dummy
implementation:

public aspect LogColourMixin {

  declare parents : TransportBean
  implements LogColour;

  public int LogColour.getLogRed() {return -999;}

}

Third, I define a "pointcut" that identifies when this method is
called, and an "advice" that does the appropriate calculation (this
goes inside LogColourMixing defined above; Tk is a static toolkit):

  pointcut beanRed(TransportBean bean):
    call(public int LogColour.getLogRed()) && target(bean);

  int around(TransportBean bean): beanRed(bean) {
    return Tk.log2(bean.getRed());

Note here that the pointcut and advice are both parameterised with a
TransportBean instance.  This gives us access to the bean inside the
advice so that we can call the getRed() method.

Coding Style
------------

The use of mixins here is completely gratuitous.  I could equally well
have added the getLogRed() method directly to the transport bean.  Or
I could have used some kind of facade.

However, this approach helps separate the different concerns.  The
presentation mixin lives with my presentation source and is not
referred to by the transport, database or business logic layers.  As
it happens, the database layer also uses a mixin to add a table key to
the object; that doesn't appear in the transport, business or
presentation code.

It Doesn't Work
---------------

While the code above does work in my test case, the tag failed!
Inside the tag, the getLogRed() method is returning -999.  The advice
is not being applied.

This is due to an implementation detail of AspectJ.  The addition of
the interface is achieved by modifying the class file - it is a static
change.  The pointcut and advice, however, are dynamic; they are
implemented by inserting tests in *calling* code.

The dynamic interception works fine in my tests because I am using
AspectJ-aware Eclipse.  But the tag files are compiled in the server
(Tomcat), which knows nothing about AspectJ and so doesn't add the
appropriate indirection.

(One solution to this is to pre-compile the tags using AspectJ).

Ugly -999
---------

And that dummy method implementation is ugly!  Here it is again:

  public int LogColour.getLogRed() {return -999;}

Why can't that be:

  public int LogColour.getLogRed() {
    return Tk.log2(getRed());
  }

Because getRed is part of the parent!  I cannot find a way to acccess
the parent class statically from within the method.  The above, and
this.getRed() both give compilation errors.

Overlapping Interface Pattern
-----------------------------

A better solution struck me on the way home from work today.  This
makes the mixing completely static and removes the ugly dummy method:

public interface LogColour {
  public int getRed();
  public int getLogRed();
}

public aspect LogColourMixin {
  declare parents : TransportBean
  implements LogColour;

  public int LogColour.getLogRed() {
    return Tk.log2(getRed());
  }
}

(I did say it was obvious in retrospect...)  All I have done is
include the getRed() method in the mixin interface.  This already
exists in TransportBean, so I don't need to re-implement it, but by
adding it to the mixin I can now call it from within the getLogRed()
implementation.

This works fine when called from code compiled in the server because
the changes are all confied to static modifications in the called
code; the calling code does not need any dynamic interceptions.

So by following this pattern I have a simple mixin: easier to
understand; more efficient; and works when called from Aspectj-unaware
code.

Andrew


-- 
`__ _ __ ___  ___| |_____   personal web site: http://www.acooke.org
/ _` / _/ _ \/ _ \ / / -_)  list: http://www.acooke.org/cute
\__,_\__\___/\___/_\_\___|  aim: acookeorg; skype: andrew-cooke

_______________________________________________
compute mailing list
compute@...
https://acooke.dyndns.org/mailman/listinfo/compute

Comment on this post