The Object Teams Blog

Adding team spirit to your objects.

Posts Tagged ‘AOP

How to kick the fly-shuttle

leave a comment »

This post was originally written on August 6th, 2013, but got lost when moving this blog. Luckily I could recover it from backup.

Software composition by “weaving”

Programming languages in the wider field of Aspect Oriented Software Development introduce some kinds of composition concepts, that cannot directly be mapped to pure Java. We got used to speaking of “weaving” as a mechanism for preparing classes in these languages for execution on the JVM, whereas a true aspect oriented virtual machine would natively perform this composition transparently and more efficiently. But with the dominance of the JVM it will be “weaving” for a long time to come.

fly-shuttle

Back in the early days, AOSD languages performed some static composition on source or class files. When OT/J entered the stage, first frameworks emerged that allowed us to hook into the class loading process, so we could do the weaving dynamically on-the-fly, without ever storing the woven classes on disk. Work is (still) in the pipe-line to support even runtime-(re)weaving.

One theme in all the development of Object Teams is: first solve the dynamic case, that’s where the challenges lie, and leave more static cases for later as an optimization. “Later” has come now.

How (not) to hook into class loading?

A little while into the development of OT/J, Java 5 was published introducing the JPLIS API and the concept of a -javaagent. Today many instrumentation tools use this facility and OT/J was among the first on this boat. So for standalone Java applications the problem is solved.

Later, while developing Eclipse plug-ins, we noticed that it wouldn’t be overly cool if you have to invoke Eclipse with a -javaagent. Not only is this very inconvenient for installation, it is also problematic (e.g., for performance) to feed all classes of Eclipse through our weaver. We were lucky again, and the Equinox Adaptor Hooks emerged right when we needed them. With these hooks we were able to integrate OT/J in a way that enables all the on-the-fly flexibility we want while at the same time it lets us control the process so that the flexibility cannot be abused. So in Equinox (or better: OT/Equinox) the problem is (more than) solved.

The fact that Eclipse Luna will no longer support these hooks was slightly alarming news for Object Teams, but that problem is already essentially solved – details to be reported soon.

I’ve heard about successful experiments running OT/J code in tomcat, but, hey, the list of application servers/containers is long, and if we need specifically crafted integration for each environment, it’s kind of difficult to argue that OT/J runs “everywhere”. Is there a generic why to kick the fly-shuttle?

fly-shuttle-2

Dynamic weaving is cool, but not having a fallback is uncool, so I finally developed the static scenario as a special case of the dynamic one: a build-time weaver for OT/J.

The little new tool is ridiculously simple: we have a weaver capable of load-time weaving. All I had to do is: create a little utility that would invoke this weaver ahead-of-time, i.e., during building.

While I’m not a big fan of Maven, in my day job Maven is a must, so I bit the bullet used the opportunity to learn a bit about development of Maven plug-ins. I was amazed to find lots of tutorials still suggesting to use API that are deprecated in Maven 3 and more surprised to read forum threads suggesting to still use that deprecated API, partly to be compatible with Maven 2 (OK?) and partly because deprecation doesn’t always mean there is an alternative (OOPS?). It’s also interesting to see, that much fundamental, up-to-date information is not available from a central source but only from tribal knowledge in hundreds of forums, blogs and whatnots. — Enough whining, on to the new stuff.

For simple projects, all you need now is a pom that looks about like this:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
    <modelVersion>4.0.0</modelVersion>
 
    <parent>
        <groupId>org.eclipse.objectteams</groupId>
        <artifactId>objectteams-parent-pom</artifactId>
        <version>2.2.0</version>
    </parent>
 
    <artifactId>OTStopwatch_Built-Time_Weaver_Example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
 
    <properties>
        <tycho.version>0.18.0</tycho.version>
        <otj.version>2.2.0</otj.version>
    </properties>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.eclipse.objectteams</groupId>
                <artifactId>objectteams-weaver-maven-plugin</artifactId>
                <version>0.8.0-SNAPSHOT</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>weave</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <teamClasses>
                        <teamClass>org.eclipse.objectteams.example.stopwatch.WatchUI</teamClass>
                        <teamClass>org.eclipse.objectteams.example.stopwatch.WatchUIAnalog</teamClass>
                    </teamClasses>
                </configuration>
            </plugin>
        </plugins>
    </build>
 
    <repositories>
        <repository>
            <id>ObjectTeamsRepository</id>
            <name>Object Teams Repository</name>
            <url>http://download.eclipse.org/objectteams/maven/3/repository</url>
        </repository>
    </repositories>
 
   <dependencies>
       <dependency>
           <groupId>org.eclipse.objectteams</groupId>
           <artifactId>objectteams-runtime</artifactId>
           <version>${otj.version}</version>
       </dependency>
   </dependencies>
</project>
 

Here we enable OT/J compilation via the parent pom, specify a repo where to get the OT artifacts, a dependency and a few versions, nothing sophisticated.

What’s new is the objectteams-weaver-maven-plugin, which is minimally configured just by specifying a list of team classes that should be woven. Oops, that’s already it.

By integrating this into your build, you’ll produce class files that can be directly executed “everywhere”, i.e., without the OT/J load-time weaver, and thus: without fiddling with the class loading process. One caveat remains: naturally, by producing the woven class files offline, it will be your responsibility to correctly feed the correct versions of class files into the classpath in the desired order. If you can’t use the load-time weaver, it won’t be able to help keep things simple.

More configuration options are documented on the plug-in’s site and more explanation using our favorite examples can be found in the wiki.

Here you have it: static weaving falls of naturally if you already have dynamic weaving. And the resulting class files can truly be run “everywhere”.

I’d be curious to hear of the first OT/J apps on Android (though personally I’d prefer ubuntu).

Advertisements

Written by Stephan Herrmann

January 28, 2014 at 18:16

Posted in Eclipse, Object Teams, OTEquinox

Tagged with , , ,

Compare Object Teams to AOP?

with 7 comments

In response to our “Hello Eclipse” I was asked about “the distinction between OT, AOP and delegation
and also Wayne suspected some overlap. So here’s an attempt at answering.

What OT/J is not

If the only problems you see with pure Java are of the kind as non-invasively adding
tracing/logging to a system, than you’re probably fine with AspectJ and OT/J does not
compete for a better solution in this discipline. This is because AspectJ is specialized
at defining sophisticated pointcuts: use powerful patterns and wildcards to capture
a large set of joinpoints that shall trigger your aspect.

I’m personally not enthusiastic about targeting problems of this category because
the focus is too narrow for my taste. So in this league where AspectJ performs best
OT/J is not applying as a replacement for AspectJ.

Goals for OT/J

Positively speaking, let’s call five toplevel goals for OT/J:

  1. powerful modules
  2. powerful ways of connecting modules
  3. maximum support for re-use
  4. evolvable architectures
  5. intuitive metaphors

Most of these goals are so broad and common place, that we’ll soon agree that
we all scream for ice cream. For (1) classes, objects and bundles are a pretty good
starting point. Not much need to improve. For (3) & (4) the proof of the pudding is
only in the eating. You can’t directly boil them down to specific language features.
(5) is what makes a language suitable for manipulation by humans, it’s the least
technical goal in the list and thus ‘difficult’ to discuss among geeks 🙂

The issue of connecting modules (2) is, however, extremely interesting and creates
the backbone for anything we can say about an architecture. And this is where OT/J
excels in my view, based on three kinds of relations:

  • OT/J takes inheritance to the extreme
  • OT/J introduces a real meaningful containment relation
  • OT/J introduces the role playing relation

Mentioning inheritance lets me add that we pay very close attention to not
side-step object orientation, but rather to put object orientation on steroids.

As I’m zooming in I will leave inheritance and containment aside for now
so as to focus on the role playing relation.

Role playing

The way role playing is defined in OT/J it is actually very similar to inheritance
with three decisive differences

  • role playing is a dynamic thing happening among runtime instances
  • role playing separates two sides of inheritance: acquisition and overriding
  • control is more fine grained as individual methods (and fields) can be acquired
    and overridden selectively

This dynamism is one of the strongest points in OT/J: roles can be added to specialise
existing instances at any point during runtime and multiple roles can specialise the same
base instance simultaneously. Neither is possible if inheritance is defined between
classes rather than instances. Yet, OT/J is not careless about possible runtime effects,
so in order for a role instance to be attached to a base instance the role’s class must
statically declare a playedBy relation to the corresponding base class. The ensures that
possible runtime effects are analysable from the source code.

Ingredients to role playing

Separating acquisition from overriding yields the following pictures of possible
communications between a role and its base
– in all pictures assume a role class with this header:

public class ARole playedBy ABase { ...
 

Here we go:

Forwarding a call due to a callout binding

Here class ABase implements baseMethod() which ARole would like to “inherit”.
It does so by this little callout declaration:

void roleMethod() -> void baseMethod(); // make baseMethod known under a new name
 

Now when a client sends a roleMethod() call to the :ARole instance, this is
automatically forwarded to the associated base instance, invoking its baseMethod().

Great, so a role may acquire individual methods from its base using callout.
No big deal so far.

Here’s the opposite direction:

This time the client talks to the :ABase instance saying “baseMethod()”.
Assume that the role has defined this callin binding:

void roleMethod() <- replace void baseMethod();
 

Now the original method call is intercepted and redirected to the role.
This has the same effect as overriding has in traditional inheritance.

The full glory only shines when both directions are involved in the same control flow:

This picture shows the role version of the template&hook pattern: :ARole inherits the
template method baseMethod2() which issues a self call to the hook method baseMethod1().
Even during this self call, method dispatch may be aware of the overridingM() in the role,
which intercepts the self call.

This situation is what is widely termed as delegation in the literature:
forwarding with the option to still override methods called within this control flow.

Comparison

Now that I have elaborated on the role playing relation in OT/J, how does it compare?
To AOP? To delegation?

Role playing vs. delegation

Role playing supports full delegation with overriding. In OT/J delegation is configured
selectively for individual methods whereas the declarative style of method bindings
keeps the effort at a minimum.

Furthermore, the effect of callin bindings can be controlled by several mechanisms
which I haven’t shown here (“team activation“, “guard predicates“), which means you
have the free choice between the weaker forwarding and the stronger delegation.

Delegation usually doesn’t imply overriding when directly addressing the base instance
as in the second picture. In OT/J you can freely choose, whether or not overriding
is effective in this situation.

Additionally, OT/J takes away the burden to manually manage the additional instances
involved in delegation. That’s what a team as the container for roles does for you.

Role playing vs. AOP

My explanation didn’t sound much like AOP, did it? The only connection here is in
the term “interception”. That’s the core mechanism that is used in both approaches.
Other than that I see little similarity.

In the same way as all languages providing dynamic method dispatch can solve a
similar set of design issues, also all languages providing method call interception
can solve similar issues. In OT/J we blend interception into the general concept
of dynamic dispatch as best as we can, so that it doesn’t stick out from other
concepts of object oriented programming. So, instead of featuring three new
concepts (“join point”, “pointcut”, “advice”) , OT/J only has callin bindings to declare
method call interception.

Two examples for those who like the details of what I mean by
“blend with other concepts”: “advice” in AspectJ is an oddish animal,
it is, e.g., impossible to override inherited advice.
Callin bindings refer to methods, which can be overridden like normal.
Also “aspects” are limited regarding inheritance: it is illegal to extend a
non-abstract aspect. Roles in OT/J have no such restriction.

All the rest

OK, role playing is key for re-using (and adapting) existing things.

Remember, role playing is only one of three strong ways in OT/J to specify connections
between modules. The enhanced inheritance and the strong containment relation
are both unrelated to AOP and delegation, but add even more value as they help to
create evolvable architectures.
It’s a major contribution of OT/J that these three ways of connecting things are not added
as isolated language features but in a way that creates the best synergy among them.

I even think that roles and teams are great metaphors representing the mechanisms
at hand in an intuitive way, but before you actually tried eating the pudding,
you may perhaps not feel this way – yet 🙂

Written by Stephan Herrmann

February 13, 2010 at 19:36