[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [equinox-dev] Aspects: problem weaving same class file in different bundles

2008/6/29 Martin Lippert <lippert@xxxxxxx>:
Hi Rowan,

I looked at your example and I think I have found the problem. Your aspect bundle imports the package "widgets" and can therefore refer to your class Widget. But since both widget bundles export the same package including the same class (Widget), the aspect definition is wired to only one of them. Therefore the code of the aspect refers to one of those Widget class definitions (this is standard Java and OSGi behavior).

Now you try to weave both widget bundles. The weaver for widget bundle 1 can weave your class successfully since this weaver sees the same class for Widget as your aspect bundle. The weaver for widget bundle 2 sees its own widget class but the aspect bundle is wired to the other one. Therefore the linkage error happens.

This seems not like a bug in Equinox Aspects nor the AspectJ weaver. Having the same class (with the same package) within different bundles seems not to be a nice design anyway. Do you have a specific reason for that? You could solve your problem by extracting an abstract superclass for your Widget classes, putting this superclass in a separate bundle and let the aspect weave against this superclass while having subclasses in your other bundles.

another possibility would be to import and export the 'widgets'
package from both widget bundles, then they would both see
the same class regardless of the order they were installed.

eg:

  Export-Package: widgets
  Import-Package: org.osgi.framework, widgets

see: http://www.osgi.org/blog/2007/04/importance-of-exporting-nd-importing.html

Just a first idea, there might be other solutions for your problem. Tell me more about why you choose this design and we could discuss alternatives, ok?

HTH,
-Martin






sorbus wrote:
Martin wrote:
Hi Rowan,

I assume the problem is that the aspect should weave the same class from >different bundles. For the aspect both Widget classes are visible (because both >should be woven) and the weaver does not know which one to use for type >resolution. But this is just a first guess on the problem... Would you submit a bug >in bugzilla for this issue?

Different aspects in different bundles with more specific supplement definitions >should workaround this problem, but I really would like to investigate this problem >in more detail (therefore the bug). Would be great if you could create a small test >case for this to reproduce.

I think the test case is a good idea (see below). I would rather you
take a look at that first before I submit a bug because I am at the
stage of learning BOTH equinox-aspects AND aspectj so possibly missed
something simple :-)

Description of problem (using a simple test case)

I have a very simple bundle (Widget) which has an Activator class and
a Widget class.

The Activator start() method prints out the Bundle Symbolic Name, then
instantiates a Widget

The Widget class looks like this:
package widgets;

public class Widget {
  private String wUID;
  public Widget() {
      init();
  }

  private void init() {
     wUID = java.util.UUID.randomUUID().toString();
     System.out.println("Widget has been assigned UID: " + wUID);
  }

  public void doSomething() {
     System.out.println("Widget " + wUID + " has done something");
  }
}

So the constructor calls the init() method which creates a random
UUID, assigns it, and prints it out.

I have two such bundles with a slightly different manifest file
(different Bundle Symbolic Name):

widgetbundle1.jar - Bundle Symbolic Name: Widget_01234
widgetbundle2.jar - Bundle Symbolic Name: Widget_56789

Example manifest file:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Widget Bundle
Bundle-SymbolicName: Widget_01234
Bundle-Version: 1.0.0
Bundle-ClassPath: .
Bundle-Activator: widgets.Activator
Import-Package: org.osgi.framework
Export-Package: widgets
Bundle-Description: Testing Aspects in OSGi...

The aspects look like this:
package widgetaspects;

import widgets.*;

public aspect MyAspects {
  pointcut doInit(Widget w):
     execution(void Widget.init(..)) && target(w);

  after(Widget w) : doInit(w)  {
     System.out.println("In the AFTER advice for doInit()");
     System.out.println("target:" + thisJoinPoint.getTarget());
     System.out.println("this:" + thisJoinPoint.getThis());
     w.doSomething();
  }
}

A pointcut is defined on the execution of the Widget init() method. In
the after advice, the Widget doSomething() method is called.

My aop.xml file looks like this:
<?xml version="1.0"?>
<aspectj>
   <aspects>
       <aspect name="widgetaspects.MyAspects"/>
   </aspects>
</aspectj>

and is installed in org/aspectj/aop.xml in the widget-aspects jar file.

Aspect bundle manifest file:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Widget Aspects
Bundle-SymbolicName: widgetaspects
Bundle-Version: 1.0.0
Export-Package: widgetaspects,org.aspectj
Import-Package: widgets
Require-Bundle: org.aspectj.runtime;visibility:=reexport
Eclipse-SupplementBundle: Widget_*
Bundle-ClassPath: .

If I install EITHER widgetbundle1 OR widgetbundle2 and the
widget-aspects bundle, then start the widgetbundle then it works and I
get this on the console:

Starting Widget Bundle: Widget_01234
[Widget_01234] weaveinfo Join point 'method-execution(void
widgets.Widget.init())' in Type 'widgets.Widget' (Widget.java:12)
advised by after advice from 'widgetaspects.MyAspects'
(MyAspects.aj:10) [with runtime test]
Widget has been assigned UID: 5356811b-3475-448e-8f9b-83a85fa98d3e
In the AFTER advice for doInit()
target:widgets.Widget@1af33d6
this:widgets.Widget@1af33d6
Widget 5356811b-3475-448e-8f9b-83a85fa98d3e has done something

If I install BOTH widgetbundles and the widget-aspects bundle, then
start one widgetbundle, that works as before. Starting the second
widgetbundle I get this on the console:

Starting Widget Bundle: Widget_56789
[Widget_56789] weaveinfo Join point 'method-execution(void
widgets.Widget.init())' in Type 'widgets.Widget' (Widget.java:12)
advised by after advice from 'widgetaspects.MyAspects'
(MyAspects.aj:10) [with runtime test]
Widget has been assigned UID: a26e7eba-b1d7-404c-b11b-c9586cfd5c82
org.osgi.framework.BundleException: Exception in
widgets.Activator.start() of bundle Widget_56789.
       at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:1018)
       at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:974)
       at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:346)
       at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:260)
       at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:252)
       at org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider._start(FrameworkCommandProvider.java:260)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:597)
       at org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter.execute(FrameworkCommandInterpreter.java:150)
       at org.eclipse.osgi.framework.internal.core.FrameworkConsole.docommand(FrameworkConsole.java:300)
       at org.eclipse.osgi.framework.internal.core.FrameworkConsole.console(FrameworkConsole.java:285)
       at org.eclipse.osgi.framework.internal.core.FrameworkConsole.run(FrameworkConsole.java:221)
       at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.LinkageError: loader constraint violation: when
resolving method
"widgetaspects.MyAspects.ajc$after$widgetaspects_MyAspects$1$ccb6ce9f(Lwidgets/Widget;Lorg/aspectj/lang/JoinPoint;)V"
the class loader (instance of
org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader) of the
current class, widgets/Widget, and the class loader (instance of
org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader) for resolved
class, widgetaspects/MyAspects, have different Class objects for the
type widgets/Widget used in the signature
       at widgets.Widget.init(Widget.java:14)
       at widgets.Widget.<init>(Widget.java:8)
       at widgets.Activator.start(Activator.java:12)
       at org.eclipse.osgi.framework.internal.core.BundleContextImpl$2.run(BundleContextImpl.java:999)
       at java.security.AccessController.doPrivileged(Native Method)
       at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:993)
       ... 14 more
Nested Exception:
java.lang.LinkageError: loader constraint violation: when resolving
method "widgetaspects.MyAspects.ajc$after$widgetaspects_MyAspects$1$ccb6ce9f(Lwidgets/Widget;Lorg/aspectj/lang/JoinPoint;)V"
the class loader (instance of
org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader) of the
current class, widgets/Widget, and the class loader (instance of
org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader) for resolved
class, widgetaspects/MyAspects, have different Class objects for the
type widgets/Widget used in the signature
       at widgets.Widget.init(Widget.java:14)
       at widgets.Widget.<init>(Widget.java:8)
       at widgets.Activator.start(Activator.java:12)
       at org.eclipse.osgi.framework.internal.core.BundleContextImpl$2.run(BundleContextImpl.java:999)
       at java.security.AccessController.doPrivileged(Native Method)
       at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:993)
       at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:974)
       at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:346)
       at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:260)
       at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:252)
       at org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider._start(FrameworkCommandProvider.java:260)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:597)
       at org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter.execute(FrameworkCommandInterpreter.java:150)
       at org.eclipse.osgi.framework.internal.core.FrameworkConsole.docommand(FrameworkConsole.java:300)
       at org.eclipse.osgi.framework.internal.core.FrameworkConsole.console(FrameworkConsole.java:285)
       at org.eclipse.osgi.framework.internal.core.FrameworkConsole.run(FrameworkConsole.java:221)
       at java.lang.Thread.run(Thread.java:619)
Nested Exception:
java.lang.LinkageError: loader constraint violation: when resolving
method "widgetaspects.MyAspects.ajc$after$widgetaspects_MyAspects$1$ccb6ce9f(Lwidgets/Widget;Lorg/aspectj/lang/JoinPoint;)V"
the class loader (instance of
org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader) of the
current class, widgets/Widget, and the class loader (instance of
org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader) for resolved
class, widgetaspects/MyAspects, have different Class objects for the
type widgets/Widget used in the signature
       at widgets.Widget.init(Widget.java:14)
       at widgets.Widget.<init>(Widget.java:8)
       at widgets.Activator.start(Activator.java:12)
       at org.eclipse.osgi.framework.internal.core.BundleContextImpl$2.run(BundleContextImpl.java:999)
       at java.security.AccessController.doPrivileged(Native Method)
       at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:993)
       at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:974)
       at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:346)
       at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:260)
       at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:252)
       at org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider._start(FrameworkCommandProvider.java:260)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:597)
       at org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter.execute(FrameworkCommandInterpreter.java:150)
       at org.eclipse.osgi.framework.internal.core.FrameworkConsole.docommand(FrameworkConsole.java:300)
       at org.eclipse.osgi.framework.internal.core.FrameworkConsole.console(FrameworkConsole.java:285)
       at org.eclipse.osgi.framework.internal.core.FrameworkConsole.run(FrameworkConsole.java:221)
at java.lang.Thread.run(Thread.java:619)

In the aspect definition I have played around with perthis and pertarget, e.g.:

public aspect MyAspects pertarget(doInit(Widget)) {......

but it has not made any difference.

Rowan
_______________________________________________
equinox-dev mailing list
equinox-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/equinox-dev




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



--
Cheers, Stuart