Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[aspectj-users] Re: Access to the aspect in 'pertypewithin' type

Hello Dean,

instead of:

> static boolean isEnabledFor(Object o) {
>   return aspectOf(o.getClass()).enabled;
> }
> before(Object o): if (isEnabledFor(o))
>   && target(o) && call (* ptw.*.*(..)) {
>   System.out.println("entering: "+thisJoinPointStaticPart);
> }

I have now:

static boolean isEnabledFor(Object o) {
  return aspectOf(o.getClass()).enabled;
}
before : if (
  isEnabledFor(
    thisJoinPointStaticPart.getSignature()
      .getDeclaringType()).isAspectTracing()))
  && execution (* ptw.*.*(..)) {
  System.out.println("entering: "+thisJoinPointStaticPart);
}

which should be quite similar in respect to execution time. (Any special reason why you used 'call' and not 'execution' pointcut?)


The Set is what I would expect a (static) member of the JDK Logging Logger to keep track of all the Loggers (as a map logger-name -> logger-instance). In the if() conditional the access to this logger (in a hand coded implementation this would be a static member of the logging class) should be as direct (fast) as possible. My target was to be able to generate aspect based JSR-47 tracing that is at least equal to the one you would write manually in terms of execution times (especially if disabled). Without all the pain and the probability to make mistakes if you have to write this logging code over and over again. Logging is the most used example when talking about AOP.


Kind Regards,

Andreas.



Dean Wampler wrote:
I played around with a few workarounds that give you type-specific enablement of tracing with checking of an if() conditional in the pointcut. It may not be as runtime efficient as we might like, but it shouldn't be too bad either.

Start with two test classes:

package ptw;

public class Type1 {
public void doit1() {
System.out.println("in: Type1.doit1()");
}
public void doit2() {
System.out.println("in: Type1.doit2()");
}
}

and

package ptw;

public class Type2 {
public void doit1() {
System.out.println("in: Type2.doit1()");
}
public void doit2() {
System.out.println("in: Type2.doit2()");
}
}

Here's the first aspect that uses pertypewithin and a static method to make the "enabled" field accessible. It also has a main that exercises the code:

package ptw;

public aspect TracerPerType pertypewithin(ptw.*) {
public boolean enabled = false;
static boolean isEnabledFor(Object o) {
return aspectOf(o.getClass()).enabled;
}


// It would be great if we could just pass the type, but we only have the object. (right?)

before(Object o): if (isEnabledFor(o)) && target(o) && call (* ptw.*.*(..)) {
System.out.println("entering: "+thisJoinPointStaticPart);
}

public static void main(String[] args) {
System.out.println("No tracing enabled:");
callDoits();
System.out.println("Enabling tracing for Type1:");
aspectOf(Type2.class).enabled = true;
callDoits();
System.out.println("Enabling tracing for Type2:");
aspectOf(Type2.class).enabled = true;
callDoits();
System.out.println("Disabling tracing for Type1:");
aspectOf(Type1.class).enabled = false;
callDoits();
System.out.println("Disabling tracing for Type2:");
aspectOf(Type2.class).enabled = false;
callDoits();
}

private static void callDoits() {
Type1 t1 = new Type1();
t1.doit1();
t1.doit2();
Type2 t2 = new Type2();
t2.doit1();
t2.doit2();
}

}

Here's a second aspect that doesn't use pertypewithin and tracks which types are enabled in a Set. It also has a main:

package ptw;
import java.util.HashSet;

public aspect Tracer {
// Don't use the <?> for Java 1.4, of course.
static HashSet<Class<?>> enabled = new HashSet<Class<?>>();
static void enableFor(Class<?> clazz) {
enabled.add(clazz);
}
static void disableFor(Class<?> clazz) {
enabled.remove(clazz);
}

before(Object o): if (enabled.contains(o.getClass())) && target(o) && call (* ptw.*.*(..)) {
System.out.println("entering: "+thisJoinPointStaticPart);
}

public static void main(String[] args) {
System.out.println("No tracing enabled:");
callDoits();
System.out.println("Enabling tracing for Type1:");
Tracer.enableFor(Type1.class);
callDoits();
System.out.println("Enabling tracing for Type2:");
Tracer.enableFor(Type2.class);
callDoits();
System.out.println("Disabling tracing for Type1:");
Tracer.disableFor(Type1.class);
callDoits();
System.out.println("Disabling tracing for Type2:");
Tracer.disableFor(Type2.class);
callDoits();
}

private static void callDoits() {
Type1 t1 = new Type1();
t1.doit1();
t1.doit2();
Type2 t2 = new Type2();
t2.doit1();
t2.doit2();
}
}

Both aspects should print out the following:

No tracing enabled:
in: Type1.doit1()
in: Type1.doit2()
in: Type2.doit1()
in: Type2.doit2()
Enabling tracing for Type1:
entering: call(void ptw.Type1.doit1())
in: Type1.doit1()
entering: call(void ptw.Type1.doit2())
in: Type1.doit2()
in: Type2.doit1()
in: Type2.doit2()
Enabling tracing for Type2:
entering: call(void ptw.Type1.doit1())
in: Type1.doit1()
entering: call(void ptw.Type1.doit2())
in: Type1.doit2()
entering: call(void ptw.Type2.doit1())
in: Type2.doit1()
entering: call(void ptw.Type2.doit2())
in: Type2.doit2()
Disabling tracing for Type1:
in: Type1.doit1()
in: Type1.doit2()
entering: call(void ptw.Type2.doit1())
in: Type2.doit1()
entering: call(void ptw.Type2.doit2())
in: Type2.doit2()
Disabling tracing for Type2:
in: Type1.doit1()
in: Type1.doit2()
in: Type2.doit1()
in: Type2.doit2()

Using a static Set or Map like this is a pretty common idiom. pertypewithin eliminated many cases for it.

dean

On Jan 31, 2008, at 11:53 AM, Andy Clement wrote:

So, from the advice you can of course just use 'this' as that will be
the aspect instance.  Your question is more about accessing the
instance from the pointcut rather than the advice as you want to check
a trace guard using if().   If it can be accessed from the if() then
the optimization to lazily build the joinpoint object for passing to
the advice is possible (using what we used to call the lazyTjp
optimization).

Unfortunately you cannot do that right now - traditionally people have
used a single global flag as the primary guard for all tracing across
the system and then within the advice checking on a per type basis.

before(): execution(public * *(..)) && if(isEnabledAnywhere) {
 if (logger.isEnabledFor(getWithinTypeName()) {
   logger.log(thisJoinPoint);
 }
}

This gives you the global control to guard building thisJoinPoint
objects - if tracing is not turned on anywhere, there is no cost for
that.  But if you enable it for any type you will suffer the building
of the tjp object across the system.

It can be optimized and has been mentioned in the past, but I haven't
gotten around to it.  There are a few open bugzilla entries related to
pertypewithin() but I don't think this requirement has been captured
explicitly - feel free to raise an enhancement request for it.

Andy


On 31/01/2008, Andreas Mandel <Andreas.Mandel@xxxxxxxxx <mailto:Andreas.Mandel@xxxxxxxxx>> wrote:
Hello Dean,

thanks for your answer. Actually I already found the documents you
pointed me to. And pertypewithin works fine with 1.4JDK, at least for
what I did till now.

My point is not the usage of 'pertypewithin' but the overhead that is
generated if an condition wants to access the object instance of the
aspect, related to the current class (DeclaringType).


I try it differently:

If a class gets a pertypewithin aspect is gets a private static
transient <aspect-class> ajc$<package>$ptwAspectInstance; member and a
method public static <aspect-class> ajc$<package>$localAspectOf() weaved
in. But accessing these static information is - as far as I found out -
not directly possible from within a if(..) condition. The only way to
get the assigned aspect is to call:
aspectOf(thisJoinPointStaticPart.getSignature().getDeclaringType())
which is very costly compared to the direct access.



A sample:

public aspect Tracing pertypewithin(*.*)
{
  public boolean mEnabled;
  public boolean isEnabled ()
  {
     return mEnabled;
  }

  [...]

  before() : !within(Tracing)
//   && if(mEnabled) not possible, needs static
     && aspectOf(
       thisJoinPointStaticPart
          .getSignature().getDeclaringType()).isEnabled()
  {
    [...]
    ... thisJoinPoint.getArgs() ....
    [...]
  }
}


So the question remains: Is this somehow possible today?



Kind Regards,

Andreas.




Dean Wampler schrieb:
It goes with the aspect declaration:

public aspect Foo pertypewithin(...mypackage.*) {  // All the types in
"mypackage".
...
}

Here's the manual page for it, which is not as easy to get to with a
google search as you would think (aspectj list traffic comes up first...)

http://www.eclipse.org/aspectj/doc/released/adk15notebook/pertypewithin.html

Here's a very long message on the aspectj-dev list that shows an example:
http://dev.eclipse.org/mhonarc/lists/aspectj-dev/msg01259.html

Also, I couldn't remember if pertypewithin actually works with JDK 1.4,
but apparently it does:
http://dev.eclipse.org/mhonarc/lists/aspectj-users/msg03995.html

Can you give us some more details about what you're trying to do?

Hope this helps!
dean

On Jan 31, 2008, at 2:10 AM, Andreas Mandel wrote:

Hello,

I'm quite new to AspectJ so please apologize that some terms might not
fully hit the target.

I tried hard to find the 'pertypewithin' keyword which allows me to do
exactly what I wanted. (Guess what - debug logging and tracing). I'm
working with a 1.4 JDK. Inspecting the generated code there is one thing
that makes me unhappy because it is not as good as it could be:

To access the DeclaringType's aspect instance in the advice I need to
call
aspectOf(thisJoinPointStaticPart.getSignature().getDeclaringType()).
This generates code that calls the static aspectOf(Class) method of the
aspect to look up the DeclaringType's aspect instance via
reflection. This simply returns a pointer back to the member that is
already statically accessible in the DeclaringType
(ajc$<...>$ptwAspectInstance).
This could be directly accessible even in the static arrear (if(...))
allowing some major improvements - but unfortunately it not exposed to
the advice.

Am I just missing an other key word to get direct access? Or is this a
feature that needs to be coded?

If needed I can give more details.


Thanks for any feedback,

Andreas.

_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx <mailto:aspectj-users@xxxxxxxxxxx>
https://dev.eclipse.org/mailman/listinfo/aspectj-users

Dean Wampler, Ph.D.
dean at objectmentor.com
http://www.objectmentor.com
See also:
http://www.aspectprogramming.com  AOP advocacy site
http://aquarium.rubyforge.org     AOP for Ruby
http://www.contract4j.org         Design by Contract for Java5




------------------------------------------------------------------------

_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx <mailto:aspectj-users@xxxxxxxxxxx>
https://dev.eclipse.org/mailman/listinfo/aspectj-users

_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx <mailto:aspectj-users@xxxxxxxxxxx>
https://dev.eclipse.org/mailman/listinfo/aspectj-users

_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx <mailto:aspectj-users@xxxxxxxxxxx>
https://dev.eclipse.org/mailman/listinfo/aspectj-users

Dean Wampler, Ph.D.
dean at objectmentor.com
http://www.objectmentor.com
See also:
http://www.aspectprogramming.com  AOP advocacy site
http://aquarium.rubyforge.org     AOP for Ruby
http://www.contract4j.org         Design by Contract for Java5




------------------------------------------------------------------------

_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/aspectj-users



Back to the top