OSGi AOP

Aus LoBmEnschEn Wiki

Wechseln zu: Navigation, Suche

Inhaltsverzeichnis

Aspektorientierte Programmierung mit dem OSGi Framework

Bisherige Ergebnisse

Das OSGi Framework erlaubt es grundsaetzlich, mehrere Anwendungen in einer einzigen virtuellen Maschine zu betreiben. Die Anwendungen muessen dazu als sogenanntes OSGi-Bundle aufgebaut sein. Dies schliesst neben dem Ausbringen als .jar Archiv einige spezielle Header in dessen META-INF/Manifest ein. Beispielsweise muss hier auf eine Activator-Klasse verwiesen werden, die dazu dient, das Bundle zu starten.

Generell sind alle Anwendungen, die innerhalb des OSGi-Frameworks laufen, streng voneinander abgeschottet. Verschiedene Mechanismen erlauben es allerdings, dass ein Bundle anderen Bundles Dienste zur Verfuegung stellen bzw. auf die Dienste anderer Bundles zurueckgreifen kann. Auf diese Weise laesst sich eine Anwendung in mehrere Teilanwendungen zerlegen, die unabhaengig voneinander entwickelt und gewartet werden koennen. Dies ist moeglich, solange die vereinbarten Schnittstellen eingehalten werden ("Design-by-Contract")

Das OSGi Framework bietet von Haus aus allerdings keine Moeglichkeit, querschneidende Belange ("crosscutting concers") zu modularisieren. Hier muss auf Frameworks zur aspektorienterten Programmierung zurueckgegriffen werden. Diese Frameworks unterscheiden sich hinsichtlich verschiedener Eigenschaftsgruppen: Definition der Aspekte, Sprachumfang hinsichtlich der Aspektdefinition, Deployment der Aspekte, Weavingzeitpunkt.


Funktionierende Konfiguration OSGi + JasCO mit JasCo-Aspekt als OSGi-Bundle:

VM -Parameter:

  • -Dosgi.parentClassloader=fwk
  • -Djasco.hotswap.excludedtypes=org.*;jugglerplugin.Activator;jascoaspectplugin.Activator
  • -Djasco.debug=true
  • -Djasco.connector.loadinterval=-1
  • -Djasco.hotswap.applicationserver=true
  • -javaagent:C:\jasco\jasco.jar

Application - Parameter:

  • -console

relevanter Activator - Code:

public void start(BundleContext context) throws Exception { Class connectorClass = Class.forName("Connector.TracingConnector"); Connector c = (Connector) connectorClass.getDeclaredMethod( "getConnector", null ).invoke(null, null); try { Jasco.loadConnector(c); } catch (Throwable e) { // TODO Auto-generated catch block e.printStackTrace(); } }

Build-Konfiguration des Jasco Aspect Plugins:

Bild:buildconfig.jpg


Runtime Classpath

Bild:rtcp.jpg


Bekannte Einschränkungen:

Das Entfernen des Konnektors scheitert, da die Connector-Registry probiert, mit Class.forName einen Klassendeskriptor zu erhalten (für redefineClasses). Class.forName probiert dann mit dem defining Classloader der ConnectorRegistry (dem System Classloader?) auf die Bundle-Klasse, aus der der Konnektor entfernt werden soll, zuzugreifen. Dies schlägt natürlich fehl. -> unlogisch, warum reicht es nicht, den Konnektor aus der Registry zu entfernen ? Der Konnektor-Code wird ja nicht direkt eingewebt...


Timings

Jasco rockt gegenüber JBoss..

Buildfile: build.xml

prepare:

  [delete] Deleting directory C:\equinox\configuration

run:

    [java] --- JAsCo Jutta system activated ---
    [java] JASCO WARNING:Automatic Connector loading disabled
    [java] JAsCo HotSwap 2: Loading and trapping application, please wait...
    [java] Listening for transport dt_socket at address: 4711


    [java] osgi>
    [java] osgi>
    [java] osgi>
    [java] osgi>

install "file:C:\jBossAOPEquinox\plugins\markus.benchmark_1.0.0.jar"

    [java] osgi> Bundle id is 1


    [java] osgi>
    [java] osgi>

install "file:C:\jascoAspectPlugin\plugins\jascoAspectPlugin_1.0.0.jar"

    [java] osgi> Bundle id is 2


    [java] osgi>
    [java] osgi>

start 1

    [java] osgi>
    [java] osgi> 1000000 cycles, avg: 1404.630118 ns, last abs 1118 ns
    [java] 2000000 cycles, avg: 1403.780971 ns, last abs 1397 ns
    [java] 3000000 cycles, avg: 1403.4672846666667 ns, last abs 1396 ns
    [java] 4000000 cycles, avg: 1403.34820675 ns, last abs 1397 ns
    [java] 5000000 cycles, avg: 1403.5187104 ns, last abs 1397 ns
    [java] 6000000 cycles, avg: 1402.933033 ns, last abs 1397 ns
    [java] 7000000 cycles, avg: 1403.0983145714285 ns, last abs 1397 ns
    [java] 8000000 cycles, avg: 1402.65034325 ns, last abs 1397 ns
    [java] 9000000 cycles, avg: 1402.829982 ns, last abs 1397 ns
    [java] 10000000 cycles, avg: 1482.1710648 ns, last abs 1397 ns
    [java] 11000000 cycles, avg: 1476.513836181818 ns, last abs 1117 ns
    [java] 12000000 cycles, avg: 1470.46638225 ns, last abs 1397 ns
    [java] 13000000 cycles, avg: 1465.3460713846155 ns, last abs 1396 ns
    [java] 14000000 cycles, avg: 1460.886350142857 ns, last abs 1397 ns
    [java] 15000000 cycles, avg: 1457.0795438666667 ns, last abs 1396 ns
    [java] 16000000 cycles, avg: 1453.971581875 ns, last abs 1397 ns
    [java] 17000000 cycles, avg: 1450.914052235294 ns, last abs 1397 ns
    [java] 18000000 cycles, avg: 1449.3466396111112 ns, last abs 1397 ns
    [java] 19000000 cycles, avg: 1446.8741586842104 ns, last abs 1397 ns
    [java] 20000000 cycles, avg: 1444.77229355 ns, last abs 1396 ns
    [java] Waiting 10 secs for next run

start 2

    [java] JAsCo prototype run-time weaver disabled!
    [java] osgi> 1000000 cycles, avg: 1480.79456 ns, last abs 1396 ns
    [java] 2000000 cycles, avg: 1459.873752 ns, last abs 1397 ns
    [java] 3000000 cycles, avg: 1453.7542923333333 ns, last abs 1397 ns
    [java] 4000000 cycles, avg: 1449.368433 ns, last abs 1396 ns
    [java] 5000000 cycles, avg: 1446.651085 ns, last abs 1397 ns
    [java] 6000000 cycles, avg: 1445.478832 ns, last abs 1396 ns
    [java] 7000000 cycles, avg: 1556.5143154285715 ns, last abs 1397 ns
    [java] 8000000 cycles, avg: 1542.459464625 ns, last abs 1397 ns
    [java] 9000000 cycles, avg: 1530.092894111111 ns, last abs 1397 ns
    [java] 10000000 cycles, avg: 1521.3481679 ns, last abs 1397 ns
    [java] 11000000 cycles, avg: 1513.8784407272726 ns, last abs 1396 ns
    [java] 12000000 cycles, avg: 1507.2231985 ns, last abs 1397 ns
    [java] 13000000 cycles, avg: 1501.8263953076923 ns, last abs 1397 ns
    [java] 14000000 cycles, avg: 1497.3959553571428 ns, last abs 1397 ns
    [java] 15000000 cycles, avg: 1493.3660951333334 ns, last abs 1397 ns
    [java] 16000000 cycles, avg: 1490.3054079375 ns, last abs 1397 ns
    [java] 17000000 cycles, avg: 1487.0285312352942 ns, last abs 1397 ns
    [java] 18000000 cycles, avg: 1484.2899322777778 ns, last abs 1397 ns
    [java] 19000000 cycles, avg: 1481.731503263158 ns, last abs 1397 ns
    [java] 20000000 cycles, avg: 1479.54414705 ns, last abs 1397 ns
    [java] Waiting 10 secs for next run

OSGi mit jBoss AOP

JasCo wird inzwischen allem Anschein nach nicht mehr gut gepflegt. Aus diesem Grund ist es anzustreben, das gleiche, was mit JasCo erreicht wurde, mit JBoss AOP hinzukriegen. Jboss AOP wird noch gepflegt, aktuelle Version ist 2.0 alpha 1. JBoss AOP funktioniert ähnlich wie JasCo.

Ant-Buildfile für OSGi mit JBoss AOP:

<?xml version="1.0" encoding="UTF-8"?>

<project default="run" name="JBoss/AOP">

  <target name="prepare">
     
     <delete dir="C:\equinox\configuration"/>
     
     <property name="jboss.aop.root" value="../jbossAOP/jboss-aop_1.5.2.GA"/>
     <property name="jboss.aop.lib" value="${jboss.aop.root}/lib"/>
     <property name="jboss.aop.lib50" value="${jboss.aop.root}/lib-50"/>

     <path id="jboss.aop.classpath">
        <fileset dir="${jboss.aop.lib}">
           <include name="*.jar"/>
        </fileset>
     </path>
     <path id="jboss.aop.classpath50">
        <fileset dir="${jboss.aop.lib50}">
           <include name="*.jar"/>
        </fileset>
     </path>
     <path id="classpath">
        <path refid="jboss.aop.classpath"/>
        <pathelement path="."/>
     </path>
     <property name="aop50jar" value="${jboss.aop.lib50}/jboss-aop-jdk50.jar"/>
     <path id="classpath50">
        <path refid="jboss.aop.classpath50"/>
        <pathelement path="."/>
        <pathelement path="C:\equinox\org.eclipse.osgi_3.2.1.R32x_v20060919.jar"/>
     </path>
     <taskdef name="aopc" classname="org.jboss.aop.ant.AopC" classpathref="jboss.aop.classpath"/>
  </target>
  
  <target name="run" depends="prepare">
     <java fork="yes" failOnError="true" className="org.eclipse.core.runtime.adaptor.EclipseStarter">
        <sysproperty key="jboss.aop.path" value="jboss-aop.xml"/>
        <sysproperty key ="jboss.aop.verbose" value="true"/>
        <sysproperty key ="osgi.parentClassloader" value="fwk"/>
        <jvmarg value="-javaagent:${aop50jar}"/>
        <jvmarg value="-Xdebug"/>
        <jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=localhost:4711"/>
        <arg value="-console"/>
        <classpath refid="classpath50"/>
     </java>
  </target>

</project>

Code zum Aspekt-Deployment:

  public void deployAspect() throws Exception
  {
     AdviceBinding binding = new AdviceBinding("execution(public void machWas->saysomething(void))", null);
     binding.addInterceptor(SimpleInterceptor.class);
     AspectManager.instance().addBinding(binding);
  }

Aktueller Stand:

Apsekt lässt sich deployen, es kommt aber folgende Fehlermeldung:

  • [java] [debug] softmatch failed for : slimplugin.machWas org.jboss.aop.advice.AdviceBinding@14cb0f66 execution(public void machWas->saysomething(void))
  • es scheint sich um ein Parser-Problem zu handeln (package.Class, ich hatte nur Class bei der Pointcut Expression)
  • bingo, mit package.Class kommt ein softmatch succeeded! Allerdings funktioniert der Aspekt insgesamt noch nicht...

Neues Problem:

  • ClassAdvisor.createInterceptorChains() : das AdviceBinding kann nicht von resolveMethodPointcut(newMethodInfos, binding) resolved werden
  • scheint auch irgendwie ein parse-Problem zu sein... schwer zu debuggen (Variablen können z.T. nicht inspected werden)
  • gnu trove source code runterladen, um zu debuggen..
  • nein geht um folgende Zeile:
  • boolean matches = binding.getPointcut().matchesExecution(this, method, chainOverridingForInheritedMethods());
  • if (!matchesParameters(node)) return Boolean.FALSE <= das schlägt fehl bei saysomething.. vielleicht Notationsproblem wegen void ?!
  • WORXT!!! new AdviceBinding("execution(public void slimplugin.machWas->saysomething())", null); ohne void als Parameter!!

Removement von Aspekten funkioniert ebenfalls mit AspectManager.instance().removeBinding(bindingName); im Activator.stop() des Aspektbundles

Timings

    [java] osgi>

install "file:C:\jBossAOPEquinox\plugins\markus.benchmark_1.0.0.jar"

    [java] osgi> Bundle id is 1


    [java] osgi>
    [java] osgi>

install "file:C:\jBossAOPEquinox\plugins\jBossAspect_1.0.0.jar"

    [java] osgi> Bundle id is 2


    [java] osgi>
    [java] osgi>

start 1

    [java] osgi>
    [java] osgi> 1000000 cycles, avg: 1423.518112 ns, last abs 1397 ns
    [java] 2000000 cycles, avg: 1420.3327415 ns, last abs 1397 ns
    [java] 3000000 cycles, avg: 1422.8673703333334 ns, last abs 1397 ns
    [java] 4000000 cycles, avg: 1422.35743175 ns, last abs 1397 ns
    [java] 5000000 cycles, avg: 1420.7447302 ns, last abs 1397 ns
    [java] 6000000 cycles, avg: 1421.1884688333334 ns, last abs 1397 ns
    [java] 7000000 cycles, avg: 1420.808804142857 ns, last abs 1396 ns
    [java] 8000000 cycles, avg: 1420.121741625 ns, last abs 1396 ns
    [java] 9000000 cycles, avg: 1425.8222146666667 ns, last abs 1397 ns
    [java] 10000000 cycles, avg: 1508.2847702 ns, last abs 1397 ns
    [java] 11000000 cycles, avg: 1499.482613 ns, last abs 1397 ns
    [java] 12000000 cycles, avg: 1492.22857575 ns, last abs 1396 ns
    [java] 13000000 cycles, avg: 1486.5109499230769 ns, last abs 1397 ns
    [java] 14000000 cycles, avg: 1481.617914 ns, last abs 1397 ns
    [java] 15000000 cycles, avg: 1477.6259188 ns, last abs 1397 ns
    [java] 16000000 cycles, avg: 1474.1616741875 ns, last abs 1396 ns
    [java] 17000000 cycles, avg: 1471.1631034117647 ns, last abs 1397 ns
    [java] 18000000 cycles, avg: 1468.2380932222222 ns, last abs 1397 ns
    [java] 19000000 cycles, avg: 1465.710922631579 ns, last abs 1397 ns
    [java] 20000000 cycles, avg: 1463.1602426 ns, last abs 1396 ns
    [java] Waiting 10 secs for next run


    [java] osgi>

start 2

    [java] osgi> jBossAspectPlugin: Aspect deployed
    [java] osgi> 1000000 cycles, avg: 1796.267072 ns, last abs 1676 ns
    [java] 2000000 cycles, avg: 1782.938087 ns, last abs 1677 ns
    [java] 3000000 cycles, avg: 1782.0427016666667 ns, last abs 1676 ns
    [java] 4000000 cycles, avg: 1779.04518175 ns, last abs 1677 ns
    [java] 5000000 cycles, avg: 1778.5170018 ns, last abs 1676 ns
    [java] 6000000 cycles, avg: 1777.0111186666666 ns, last abs 1676 ns
    [java] 7000000 cycles, avg: 1778.779259857143 ns, last abs 1397 ns
    [java] 8000000 cycles, avg: 1778.156438375 ns, last abs 1676 ns
    [java] 9000000 cycles, avg: 1776.4887715555556 ns, last abs 1676 ns
    [java] 10000000 cycles, avg: 1776.3143455 ns, last abs 1677 ns
    [java] 11000000 cycles, avg: 1775.51605 ns, last abs 1397 ns
    [java] 12000000 cycles, avg: 1775.2472915833334 ns, last abs 1677 ns
    [java] 13000000 cycles, avg: 1774.7445844615384 ns, last abs 1676 ns
    [java] 14000000 cycles, avg: 1775.7234307142858 ns, last abs 1676 ns
    [java] 15000000 cycles, avg: 1775.6792701333334 ns, last abs 1676 ns
    [java] 16000000 cycles, avg: 1775.1211048125 ns, last abs 1676 ns
    [java] 17000000 cycles, avg: 1775.2864591764705 ns, last abs 1677 ns
    [java] 18000000 cycles, avg: 1774.9882241666667 ns, last abs 1676 ns
    [java] 19000000 cycles, avg: 1774.705701631579 ns, last abs 1676 ns
    [java] 20000000 cycles, avg: 1774.68814865 ns, last abs 1676 ns
    [java] Waiting 10 secs for next run

uninstall 2

    [java] jBossAspectPlugin: Aspect undeployed
    [java] osgi> 1000000 cycles, avg: 1418.972166 ns, last abs 1397 ns
    [java] 2000000 cycles, avg: 1419.178968 ns, last abs 1397 ns
    [java] 3000000 cycles, avg: 1420.3044436666667 ns, last abs 1397 ns
    [java] 4000000 cycles, avg: 1418.72162225 ns, last abs 1397 ns
    [java] 5000000 cycles, avg: 1418.6618182 ns, last abs 1397 ns
    [java] 6000000 cycles, avg: 1418.3219753333333 ns, last abs 1397 ns
    [java] 7000000 cycles, avg: 1418.180501 ns, last abs 1396 ns
    [java] 8000000 cycles, avg: 1419.31942225 ns, last abs 1397 ns
    [java] 9000000 cycles, avg: 1419.1572197777778 ns, last abs 1396 ns
    [java] 10000000 cycles, avg: 1419.3427264 ns, last abs 1397 ns
    [java] 11000000 cycles, avg: 1419.9910249090908 ns, last abs 1397 ns
    [java] 12000000 cycles, avg: 1420.216742 ns, last abs 1397 ns
    [java] 13000000 cycles, avg: 1420.1063556923077 ns, last abs 1397 ns
    [java] 14000000 cycles, avg: 1420.2673634285713 ns, last abs 1397 ns
    [java] 15000000 cycles, avg: 1420.5970298666666 ns, last abs 1396 ns
    [java] 16000000 cycles, avg: 1420.9865810625 ns, last abs 1397 ns
    [java] 17000000 cycles, avg: 1420.9710594705882 ns, last abs 1397 ns
    [java] 18000000 cycles, avg: 1420.8745016666667 ns, last abs 1397 ns
    [java] 19000000 cycles, avg: 1420.9480543157895 ns, last abs 1396 ns
    [java] 20000000 cycles, avg: 1420.9750406 ns, last abs 1397 ns
    [java] Waiting 10 secs for next run

Batchvorgang abbrechen (J/N)? ^C

AJEER - AspectJ Enabled Eclipse Runtime

AJEER - entwickelt von Martin Lippert - erlaubt es, in AspectJ geschriebene Aspekte als OSGi Bundles in das OSGi Framework zu integrieren. Allerdings ist mit AJEER nur Load-Time Weaving moeglich, das heisst, bereits geladene Klassen werden nicht beeinflusst. Die von AJEER benutzte Deployment Methode - die Integration der Aspekte als OSGi Bundle ist anzustreben. -> wie funktioniert AJEER genau - und was ist mit AOSGI - das ist doch jetzt schon verfuegbar?

OSGi Fragment-Bundles

Ein Fragment ist ein Bundle, das an ein anderes Bundle (seinem Host-Bundle), angehaengt ist. Die Komponenten des Fragmentes, wie z.B. der Bundle-Classpath und andere Definitionen, werden an die entsprechenden Definitionen des Host-Bundles angehaengt. Alle Klassen und Resourcen des Fragment-Bundles muessen vom Class Loader des Host Bundles geladen werden. Fuer den Fall des Export-Package Headers werden Bundle-abhaengige Attribute wie bundle-version und bundle-symbolic-name vom Host genommen.

Fragmente

  • sind an ein Host-Bundle angehängt (attached)
  • Fragments are therefore treated as part of the host, including any permitted headers;
  • they must not have their own class loader.
  • Fragments must have their own Protection Domain.

When attaching a fragment bundle to a host bundle the Framework must perform the following steps:

  • Append the import definitions for the Fragment bundle that do not conflict with an import definition of the host to the import definitions of the host bundle.
  • Append the Require-Bundle entries of the fragment bundle that do not conflict with a Require-Bundle entry of the host to the Require-Bundle entries of the host bundle.
  • Append the export definitions of a Fragment bundle to the export definitions of the host bundle unless the exact definition (directives and attributes must match) is already present in the host. Fragment bundles can therefore add additional exports for the same package name. The bundle-versio attributes and bundle-symbolic-name attributes will reflect the host bundle.

OSGi Extension Bundles

3.15 Extension Bundles Extension bundles can deliver optional parts of the Framework implementation or provide functionality that must reside on the boot class path. These packages cannot be provided by the normal import/export mechanisms. Boot class path extensions are necessary because certain package implementations assume that they are on the boot class path or are required to be available to all clients. An example of a boot class path extension is an implementation of java.sql such as JSR 169. Framework extensions are necessary to provide implementation aspects of the Framework. For example, a Framework vendor could supply the optional services like Permission Admin service and Start Level service with Framework extension bundles. An extension bundle should use the bundle symbolic name of the implementation system bundle, or it can use the alias of the system bundle, which is system.bundle.

AOSGI

Beteiligte Bundles:

  • org.aspectj.osgi - Fragmentbundle mit Host org.eclipse.osgi; exportiert org.aspectj.osgi.service (=> org.eclipse.osgi exportiert org aspectj.osgi.service)

Wird mittels des seit der Equinox-Version 3.2 verfügbaren AdaptorHooks-Mechanismus eingebunden:

osgi.framework.extensions=org.aspectj.osgi

Die entsprechende hookconfigurators.properties Datei verweist auf org.aspectj.osgi.hooks.AspectJHook, der AbstractAspectJHook erweitert. Der AbstractAspectJHook registriert, wie man an nachfolgendem Code-Fragment erkennen kann, sich selbst als verschiedene Hooks. Lediglich als StorageHook wird ein AspectJStorageHook registriert. hooks.addAdaptorHook(this); hooks.addClassLoadingHook(this); hooks.addBundleFileWrapperFactoryHook(this); hooks.addClassLoadingStatsHook(this); hooks.addStorageHook(new AspectJStorageHook());

Wie erkennt AOSGi ob ein Aspekt-Bundle geladen wird?

Hi Matthew,

thanks a lot for taking the time! This helps me pretty much. Can you please answer me one more question: How does the AOSGi system recognize if a bundle is an aspect bundle? Simply by looking for an aop.xml?

Yes. It's actually AspectJ (the org.aspectj.weaver bundle) that looks for the file rather than AOSGi (the org.aspectj.osgi fragment). In the long term this piece of AspectJ meta-data could be merged with OSGi meta-data (manifest.mf). For the moment we just take advantage of the OSGi meta-data to determine which aspect bundles to use through Import-Package, Require-Bundle or Eclipse-SupplementXXX.




AOSGi without Eclipse:

config.ini:

osgi.bundles=org.eclipse.equinox.common@2\:start,org.eclipse.update.configurator@3\:start,org.eclipse.core.runtime@start, org.aspectj.osgi.service.weaving@:start, org.aspectj.weaver@:start, org.aspectj.runtime@:start, org.eclipse.core.jobs@:start, org.eclipse.equinox.registry@:start, org.eclipse.equinox.preferences@:start, org.eclipse.core.contenttype@:start osgi.bundles.defaultStartLevel=4 osgi.framework=org.eclipse.osgi osgi.configuration.cascaded=false osgi.splashPath=platform:/base/plugins/org.eclipse.platform

  1. AOSGi

osgi.framework.extensions=org.aspectj.osgi org.aspectj.weaver.loadtime.configuration=META-INF/aop.xml;org/aspectj/aop.xml;META-INF/aop-ajc.xml aj.weaving.verbose=true org.aspectj.weaver.showWeaveInfo=true org.aspectj.osgi.verbose=true

Benötigte Bundles:

Bild:aosgibundles.jpg


build.xml:

<?xml version="1.0" encoding="UTF-8"?>

<project default="run" name="JBoss/AOP">

  <target name="prepare">      
     <path id="aosgi.classpath">
      <fileset dir="C:\AOSGi">

<include name="*.jar"/>

      </fileset>
     </path>
     
     <path id="classpath">
        <pathelement path="C:\AOSGi\org.eclipse.osgi_3.2.1.R32x_v20060919.jar"/>
    	 <path refid="aosgi.classpath"/>
        <pathelement path="."/>
     </path>
  </target>
  
  <target name="run" depends="prepare">
     <java fork="yes" failOnError="true" className="org.eclipse.core.runtime.adaptor.EclipseStarter">
        <arg value="-console"/>
        <classpath refid="classpath"/>
     </java>
  </target>


</project>

Wichtig ist hier, dass das org.eclipse.osgi-jar vor allen anderen Jars im classpath steht. Ansonsten werden die StorageHooks in falscher Reihenfolge erzeugt bzw ausgeführt, was beim Laden von Aspekt-Bundles zu einer NPE führen kann. Wichtig ist ausserdem, dass das supplementing Bundle vor dem supplemented Bundle geladen wird.

Info zu AOSGI:

The co-opt model allows an aspect bundle to specify the set of bundles that should be woven with the aspects it contains. This is done through manifest entries that have the same semantics as if each target bundle had used "Require-Bundle". Wildcards can be used to specify bundles based on name, the set of packages a bundle imports or the set it exports.


Info zu AOSGI:

Phase II:

The co-opt model allows an aspect bundle to specify the set of bundles that should be woven with the aspects it contains. This is done through manifest entries that have the same semantics as if each target bundle had used "Require-Bundle". Wildcards can be used to specify bundles based on name, the set of packages a bundle imports or the set it exports.


Neues Problem:

OSGiWeavingAdaptor(ClassLoaderWeavingAdaptor).registerDefinitions(BcelWeaver, ClassLoader, List) line: 244

install "file:C:\markus.benchmark_1.0.0.jar"

    [java] [org.aspectj.osgi] info supplementing markus.benchmark with [markus.aosgiaspect]
    [java] osgi> Bundle id is 16


    [java] osgi>
    [java] osgi>

start 16

    [java] [org.aspectj.osgi.service.weaving] info Starting AspectJ weaving service ...
    [java] [markus.benchmark] info AspectJ Weaver Version 1.5.3 built on Wednesday Nov 22, 2006 at 11:18:15 GMT
    [java] [markus.benchmark] info register classloader markus.benchmark
    [java] [markus.benchmark] info using configuration markus.aosgiaspect/org/aspectj/aop.xml
    [java] [markus.benchmark] info using configuration markus.aosgiaspect/org/aspectj/aop.xml
    [java] [markus.benchmark] info register aspect markus.aspect.myAspect
    [java] [markus.aosgiaspect] info AspectJ Weaver Version 1.5.3 built on Wednesday Nov 22, 2006 at 11:18:15 GMT
    [java] [markus.aosgiaspect] info register classloader markus.aosgiaspect
    [java] [markus.aosgiaspect] info using configuration markus.aosgiaspect/org/aspectj/aop.xml
    [java] [markus.aosgiaspect] info using configuration markus.aosgiaspect/org/aspectj/aop.xml
    [java] [markus.aosgiaspect] info register aspect markus.aspect.myAspect

Aspekt Frameworks, die Runtime Weaving beherrschen

Hierzu zaehlen JAsCo, AspectWerkz und JBoss AOP. Alle diese Frameworks greifen auf die im Java-Sprachumfang enthaltene "Javaagent" - Technologie zurueck, um den Bytecode bereits geladener Klassen zur Laufzeit zu veraendern. !!! Identifikation zu instrumentierender Klassen bei diesen Frameworks nur anhand des Namens - was ist, wenn Klassen gleichen Names in verschiedenen Bundles enthalten sind? Normalerweise ja Identifikation anhand des Class Loaders... Vielleicht via Bundlename als packagename? !!!

-- Diagramm javaagent/instrumentation/transformer --

Besonderheiten des OSGi Class Loadings

Viele Leute glauben, dass eine Klasse in Java eindeutig ueber ihren Namen identifiziert wird. Dies ist jedoch falsch. Eine Klasse wird eindeutig identifiziert durch ein Tupel <CL,N> wobei CL der "defining ClassLoader" und N der "binary Name" der Klasse ist. Auf diese Weise ist es moeglich, eine Klasse gleichen names hundertmal zu laden, solange dafuer hundert verschiedene Classloader verwendet werden.

OSGi macht sich diesen Mechanismus zunutze um verschiedene Versionen eines Bundles oder Klassen gleichen Namens in verschiedenen Bundles laden zu koennen. Zu diesem Zweck erzeugt das OSGi Framework pro Bundle einen eigenen Classloader.

Klassen, die am Class Loading in OSGi beteiligt sind

Bild:osgi_klassendiagramm.png

Erläuterungen laut OSGi-JavaDoc:

A ClassLoaderDelegate is used by the BundleClassLoader in a similar fashion that a parent ClassLoader is used. A ClassLoaderDelegate must be queried for any resource or class before it is loaded by the BundleClassLoader. The Framework implements the ClassLoaderDelegate and supplies it to the BundleClassLoader. FrameworkAdaptor implementations are not responsible for suppling an implementation for ClassLoaderDelegate.

BundleLoader: This object is responsible for all classloader delegation for a bundle. It represents the loaded state of the bundle. BundleLoader objects are created lazily; care should be taken not to force the creation of a BundleLoader unless it is necessary.

The BundleClassLoader interface is used by the Framework to load local classes and resources from a Bundle. Classes that implement this interface must extend java.lang.ClassLoader, either directly or by extending a subclass of java.lang.ClassLoader. ClassLoaders that implement the BundleClassLoader interface must use a ClassLoaderDelegate to delegate all class, resource and native library lookups.

BaseClassLoader: The actual class loader object used to define classes for a classpath manager. This interface provides public versions of a few methods on class loader.

DefaultClassLoader: The default implemention of BaseClassLoader. This implementation extends java.lang.ClassLoader.

BaseAdaptor: Repräsentiert, grob gesagt, das OSGi-Framework


Im Prinzip läuft es so: Erfolgt der Start eines Bundles, so lädt das Framework zunächst dessen Activator-Klasse (lt. Manifest). Dazu erzeugt das Framework einen "DefaultClassLoader". Dieser defined die Activator Klasse. Trifft die Ausführung im nun erzeugten Objekt der Activator-Klasse auf eine neue symbolische Referenz (siehe Java Virtual Machine Specification, Kapitel 5.4.3.1), so versucht die Virtual Machine mit dem Defining Class Loader der Activator Klasse (also dem Default Class Loader), die Klasse der symbolischen Referenz zu laden. Der Default Class Loader delegiert an seinen delegate-Member, dieser ist vom Typ ClassLoaderDelegate. Hier erfolgt analog OSGi-Spezifikation entlang einer festgelegten Reihenfolge der Resolving-Prozess für diese Klasse..

Wie gelange ich zur Laufzeit an den Bytecode bereits geladener Klassen?

  • doppelte Buchaltung: Transformer speichert den initialen Bytecode in assoziativer Datenstruktur -> ineffizient
  • via Classloader: getResourceAsStream (hat irgendwie noch nie geklappt)
  • retransformClasses: sehr elegante Moeglichkeit, allerdings erst ab Java 2 SE 6.0 verfuegbar

AspectJ

Spezielle Patterns, um mit AspectJ gewisse Runtime Weaving Funktionalitaeten nachzubilden

AOP Frameworks

JAsCo

AspectWerkz

JBoss AOP

AJEER - AspectJ Enabled Eclipse Runtime

Neu: AspectJ Equinox Framework Extension

The Spring Framework

OSGi Internals

OSGi Specifications

Media:OSGIR4.pdf

"Die" Implementation: Equinox

Runtime Options von Eclipse bzw Equinox

OSGi-Blog

OSGi Bundle Repository (1000+ Bundles)

Adaptor Hooks in Eclipsepedia

Java Internals

Java API Specification - Java 2 SE 6.0 b104

Java API Specification - Java 2 SE 5.0

Java Virtual Machine Specification

Java Language Specification

ONJAVA: Internals of Java Class Loading

Forumsdiskussion Java Class Loading und Thread.setContextClassloader

Forumsdiskussion zu Class Schema Changes Integration in Java 7

Thesis mit Hotspot Data Structures in Kapitel 7.1

Persönliche Werkzeuge