Simple Hello World demonstrating OSGi with Akka Actors? - scala

I want to create a very simple (Hello Simple World) POC that demonstrates the ability to integrate OSGi (Felix) with Scala and Actors (Akka). Here is what I have so far:
$ tree
.
├── bin
│   └── felix.jar
├── bundle
│   └── akka-osgi_2.10-2.2.1.jar
├── conf
    └── config.properties
$ cat conf/config.properties
org.osgi.framework.storage.clean: onFirstInit
org.osgi.framework.system.packages.extra: javafx
org.osgi.framework.bootdelegation: sun.misc
felix.auto.deploy.action=install,start
felix.log.level=1
org.osgi.service.http.port=8080
obr.repository.url=http://felix.apache.org/obr/releases.xml
$ java -jar bin/felix.jar
ERROR: Bundle com.typesafe.akka.osgi [1] Error starting file:/home/axiopisty/projects/test/bundle/akka-osgi_2.10-2.2.1.jar (org.osgi.framework.BundleException: Unresolved constraint in bundle com.typesafe.akka.osgi [1]: Unable to resolve 1.0: missing requirement [1.0] osgi.wiring.package; (&(osgi.wiring.package=com.typesafe.config)(version>=0.4.1)(!(version>=1.1.0))))
org.osgi.framework.BundleException: Unresolved constraint in bundle com.typesafe.akka.osgi [1]: Unable to resolve 1.0: missing requirement [1.0] osgi.wiring.package; (&(osgi.wiring.package=com.typesafe.config)(version>=0.4.1)(!(version>=1.1.0)))
at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:3974)
at org.apache.felix.framework.Felix.startBundle(Felix.java:2037)
at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1291)
at org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:304)
at java.lang.Thread.run(Thread.java:744)
I understand from this error message that there is no bundle that exports osgi.wiring.package. But I don't know which bundle I would need to include that exports that package. Would it come from Akka, from Felix, or from somewhere else?
As can be seen in the provided config.properties I tried to follow the instructions about how to Configure the OSGi Framework from the akka documentation, but I don't know if I'm doing what they said needs to be done in the right way.
The akka documentation says:
To use Akka in an OSGi environment, the
org.osgi.framework.bootdelegation property must be set to always
delegate the sun.misc package to the boot classloader instead of
resolving it through the normal OSGi class space.
How do you do this using Felix as the OSGi container, and using the default felix launcher?
A simple hello world example using OSGi (Felix is not required, but preferred) and Akka Actors is ideally what I'm looking for. If you know of anything on github (or elsewhere) that demonstrates this, I would accept that as an answer too.

There is a sample OSGi application in the Akka source tree. Hopefully you can use it as a staring point. It uses Karaf.
https://github.com/akka/akka/tree/v2.2.3/akka-samples/akka-sample-osgi-dining-hakkers
Make sure to check out the code at a stable tag, like v2.2.3 so the build tools use published stable artifacts of Akka.

missing requirement [1.0] osgi.wiring.package; (&(osgi.wiring.package=com.typesafe.config)
From this part of your error message it seems that your bundle cannot find another bundle that provides com.typesafe.config which is a dependency of akka.
You can circumvent this with the Conditional-Package Header/Instruction of the bnd tool when you create your bundle.

I have started to put an OSGi container based on Karaf together and have shared it on github. For now it simply registers an ActorSystem as a service and has a demo bundle with an Actor in it using that system. It is configured to log into the normal karaf.log.
The code example can be found on github.
Best regards
Andreas

Related

AspectJ with jar classloader

I am trying to instrument Oracle Rest Data Service (ORDS) which is built on Jetty. The aspect should trace JDBC calls. I do not see the weaving happening.
I have tried AspectJ in a different standalone application which used JDBC and also profiled Servlet calls in an application running in standalone Jetty and all this worked for me. But in this case there is an exception and it does not look that weaving is happening. Application itself works as expected with all AspectJ configurations applied.
Two options have been tried:
aspect class and aop configuration file were put into jar and this jar was placed inside WEB-INF/lib. aspectjrt.jar was copied into this directory as well.
the aspect class and aspect config were copied into WEB-INF/classes
like this
├── WEB-INF
│ ├── beans.xml
│ ├── classes
│ │ ├── META-INF
│ │ │ ├── MANIFEST.MF
│ │ │ └── aop-ajc.xml
│ │ └── WhereTheStatementTimeGo.class
There was an exception like below in both cases.
Here is the command line and the exception:
$JAVA_HOME/bin/java -javaagent:/DATA/PROJECTS/ASPECTJ19/lib/aspectjweaver.jar -Dorg.aspectj.tracing.enabled=true -Dorg.aspectj.tracing.factory=defaug.aspectj.tracing.messages=true -jar ords.war standalone
[JarClassLoader#17f052a3] warning parse definitions failed -- (IllegalStateException) sun.misc.Launcher$AppClassLoader#18b4aac2
sun.misc.Launcher$AppClassLoader#18b4aac2
java.lang.IllegalStateException: sun.misc.Launcher$AppClassLoader#18b4aac2
at oracle.dbtools.jarcl.NestedResourceHandler.jarClassLoader(NestedResourceHandler.java:36)
at oracle.dbtools.jarcl.NestedResourceHandler.openConnection(NestedResourceHandler.java:23)
at java.net.URL.openConnection(URL.java:979)
at java.net.URL.openStream(URL.java:1045)
at org.aspectj.weaver.loadtime.definition.DocumentParser.saxParsing(DocumentParser.java:157)
at org.aspectj.weaver.loadtime.definition.DocumentParser.parse(DocumentParser.java:123)
at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.parseDefinitions(ClassLoaderWeavingAdaptor.java:290)
at org.aspectj.weaver.loadtime.DefaultWeavingContext.getDefinitions(DefaultWeavingContext.java:130)
at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.initialize(ClassLoaderWeavingAdaptor.java:174)
at org.aspectj.weaver.loadtime.Aj$ExplicitlyInitializedClassLoaderWeavingAdaptor.initialize(Aj.java:337)
at org.aspectj.weaver.loadtime.Aj$ExplicitlyInitializedClassLoaderWeavingAdaptor.getWeavingAdaptor(Aj.java:342)
at org.aspectj.weaver.loadtime.Aj$WeaverContainer.getWeaver(Aj.java:316)
at org.aspectj.weaver.loadtime.Aj.preProcess(Aj.java:108)
at org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:51)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at oracle.dbtools.jarcl.JarClassLoader.findClass(JarClassLoader.java:77)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at oracle.dbtools.jarcl.Entrypoint.invoke(Entrypoint.java:50)
at oracle.dbtools.jarcl.Entrypoint.main(Entrypoint.java:77)
2019-07-02 16:47:29.822:INFO::main: Logging initialized #3375ms to org.eclipse.jetty.util.log.StdErrLog
Jul 02, 2019 4:47:29 PM
INFO: HTTP and HTTP/2 cleartext listening on port: 8080
Jul 02, 2019 4:47:29 PM
INFO: Disabling document root because the specified folder does not exist: /Users/slinetsk/Downloads/ORDS/ords/standalone/doc_root
2019-07-02 16:47:30.632:INFO:oejs.Server:main: jetty-9.4.z-SNAPSHOT; built: 2019-02-20T15:50:58.683Z; git: 3285c4dd4bb00caddcded77f8e44e72c61b9ab72; jvm 1.8.0_211-b12
2019-07-02 16:47:30.693:INFO:oejs.session:main: DefaultSessionIdManager workerName=node0
2019-07-02 16:47:30.693:INFO:oejs.session:main: No SessionScavenger set, using defaults
2019-07-02 16:47:30.694:INFO:oejs.session:main: node0 Scavenging every 600000ms
There was no any AspectJ tracing related info in the output
I found a workaround which lets me run the server without problems and also use different types of aspect pointcuts on all sorts of classes such as internal Jetty classes:
Copy the AspectJ weaver and your aspect library (JAR containing aspects and META-INF/aop.xml) to a subdirectory lib of where you are starting your ords.war. Then append the aspect library to the JVM boot classpath. You need to use a JRE/JDK version like Java 8 which actually still supports the boot classpath. (Actually I just checked, JDK 11 still supports it.) I don't know how to do this with modularised JREs. Then start your WAR like this:
java -Xbootclasspath/a:lib/aspect.jar -javaagent:lib/aspectjweaver.jar -jar ords.war standalone
One more time, with line breaks inserted:
java
-Xbootclasspath/a:lib/aspect.jar
-javaagent:lib/aspectjweaver.jar
-jar ords.war standalone
This approach makes sure that the weaver is attached and its as well as the aspect classes are found before the Oracle JAR classloader does its entry point magic.
Please note that you do not need to modify the WAR file at all here.
Update: As an alternative you could attach the AspectJ weaving agent dynamically instead of via -javaagent, see
my other answer
AspectJ feature description
I quickly tested it, it works. It is kind of tricky, though:
You would have to put your own main class similar to the one in the AspectJ read-me into the WAR as main class. That class would attach the weaver and then start the JAR classloader. Now the weaver is already in place and everything works as expected.
A caveat is that you need to start the JVM with tools.jar, myaspect.jar and aspectjweaver.jar on the classpath,
either on boot classpath if you want to start the application with java -jar my.war
or on the normal classpath You if it is okay to start the application with -cp ...;my.war my.own.MainClass.
Also since Java 9 there is no tools.jar anymore but you need to make your own entry point class dependent on the module jdk.attach and also make sure that you actually run the application with a JDK, not a JRE. Otherwise you cannot use the API for dynamically attaching agents.
All in all I still favour the original solution, it is much easier to implement.

Can't use akka in IDEA plugin development

When I develop an IDEA plugin, I want to use akka, but have some problems.
I created a demo project here: https://github.com/freewind/idea-plugin-akka-demo
You can just clone it and reproduce the problem on your computer. (Notice the Setup section)
And I copy the problem here:
Problems
1. Can't use default akka configuration
If I removed:
src/main/resources/application.conf
src/main/scala/freewind/MyAkkaConfig
and run this plugin, it will report this error when starting:
com.intellij.ide.plugins.PluginManager$StartupAbortedException:
com.intellij.diagnostic.PluginException: No configuration setting found for key 'akka'
[Plugin: com.yourcompany.unique.plugin.id]
2. Can't load the configuration from file
Then I copied the reference.conf from akka jar, to src/main/resources/application.conf, but it still report the same error. Seems akka in IDEA plugin can't find this file automatically.
3. ClassNotFoundException: akka.actor.LightArrayRevolverScheduler
So I have to use MyAkkaConfig.scala to hardcode the configuration in scala code, but this time, it reports another error:
com.intellij.ide.plugins.PluginManager$StartupAbortedException:
com.intellij.diagnostic.PluginException: ClassNotFoundException: akka.actor.LightArrayRevolverScheduler
[Plugin: com.yourcompany.unique.plugin.id]
The akka.actor.LightArrayRevolverScheduler is used in MyAkkaConfig.scala, and is included in akka-actor_2.11:2.3.12:jar. But why IDEA can't load it?
For the 3rd problem, it can be fixed by passing the classloader:
val system = ActorSystem("my-actor", MyAkkaConfig.config, this.getClass.getClassLoader)
But we also can remove the MyAkkaConfig.config, to use the file application.conf under resources

How to get Dependency chain in Apache Karaf (Felix framework)

I am getting uses constraint violation as below while installing a feature in Apache Karaf (karaf framework is felix and version is 4.2.1)
could not be resolved. Reason: Package uses conflict: Import-Package: org.apache.http.entity; version="0.0.0"
After googling , came to know that "Dependency Chain" can help in root causing the issue. but I do not know the steps to follow to get this dependency chain printed in the logs or osgi console
Example Dependency chain is given in the below URL:
Dependency chain conflicts for Hibernate and Apache Felix
Thanks in advance
If you use the felix framework this should be printed either on the console and/or in the logfile while starting the bundle.
With Karaf you also can take a look at bundle:tree-show [bundle-id]. This will show you all bundles your bundle depends on.

Karaf unresolved constraint JDBC

I am trying to get a Scala library using H2 database loading in Karaf 3.0.0-RC1 and I got this error
Unresolved constraint in bundle org.h2 [86]: Unable to resolve 86.0: missing requirement
[86.0] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.service.jdbc)(version>=1.0.0)
Does anyone know what I need to add to POM and / or feature.xml to get this working?
Thanks,
Bob
You need that jar that contains the package. To get it:
go to http://search.maven.org
Push Advanced search
To the Classname, type "org.osgi.service.jdbc"
You will get a list of dependencies that contain the package. For example, the first one will be good for you: http://search.maven.org/#artifactdetails|org.ow2.spec.osgi|ow2-jdbc-service-1.0-spec|1.0.13|bundle
Btw.: The package originally comes from the OSGi enterprise spec (or compendium, do not remember). As much as I saw all of the OSGi spec packages are available in ow2 dependencies that separated logically.
In Karaf, there might be other ways to get the dependency you need but I did not use Karaf in the past.

Scala in OSGI container?

How can I code my bundle in Scala and then deploy it into OSGI container?
Do I compile it into "java" first or can i deploy scala straight into OSGI and use some kind of bundles to recognize it?
Any pointers would be great.
Currently I am using Apache Felix as my osgi-container, but just a simple explanation of generic concepts would suffice to get me started.
Thanks to everyone for the answers, you led me to the solution! I will describe it here in a little simpler terms for a wider audience.
Goal: Code in scala, deploy to OSGi.
Tools used:
Equinox OSGi implementation
Eclipse Helios 3.6,
Scala 2.9
Procedure
Install Scala IDE for Eclipse. Find version that will work with Scala 2.9 and Eclipse 3.6
Create new Scala Project in Eclipse.
Convert the project to OSGi bundle by right clicking on it and selecting: Configure -> Convert to Plug-in Projects...
Now, the next part was where I got stuck. You see, now we need to deploy this bundle (our project) to OSGi environment. However we are missing the Scala classes (or bundle that contains those classes) that have to be in OSGi container to provide all the Scala packages API we use in our bundle. Unfortunately finding the "Scala bundle" is not that easy. After looking around it turns out, that for some reason, Scala bundle is actually located in the Sonatype Maven Repository.
Download the scala-library-2.9.1.jar from the appropriate location in the Sonatype Maven Repository, and deploy it (by means most comfortable for you) to your OSGi container.
Adjust your manifest file to require the Scala bundle (I am pretty sure that this is one place where bundle dependency (i.e. Require-Bundle) is actually pretty safe - after all, you will never run your Scala code without Scala!):
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Scala Hello
Bundle-SymbolicName: com.test.scala.hello
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: drozzy
Import-Package: org.osgi.framework;version="1.5.0"
Bundle-Activator: com.test.scala.hello.Activator
Require-Bundle: scala-library;bundle-version="2.9.1"
Now, you can write your bundle activator in Scala (wooho!):
//Activator.scala
package com.test.scala.hello
import java.lang.System
import org.osgi.framework.BundleActivator
import org.osgi.framework.BundleContext
class Activator extends BundleActivator {
def start(context: BundleContext) {
System.out.println("Hello world from scala!");
}
def stop(context: BundleContext){}
}
Deploy your project as a bundle to OSGi container and look out for the "Hello world from scala!" message.
ScalaModules
A quick intro video by the author here Scala days 2010
OSGi does not care what language you write your code in: JVM bytecode is just JVM bytecode. So:
compile with Scala
wrap the resulting classes in a bundle using bnd (just as you would for code compiled from Java sources).
deploy the bundle to OSGi, just as you would for a "normal" bundle (because it is a normal bundle).
You'll notice that your bundle has dependencies on the Scala library. Again there is nothing strange about this, it's just like having dependencies in you Java code. In order for those dependencies to resolve, you need to install the Scala library bundle from scala-lang-osgi
There is nothing special to it: write your code in Scala and wrap it up as an OSGi bundle by providing the necessary bundle meta data and service descriptors as you would do with Java.
Apache Maven can help you in the process. Have a look at the Guggla Project (a Scala script engine) for a working example. The maven-bundle-plugin in the pom.xml takes care of generating and including the bundle meta data in the final jar file. It refers to the service descriptor xml file which you need to provide.