I'm starting an OSGI Spring DM based Swing application. The app should start and show up when the bundle is loaded. I know that this can be achieved with an activator class configured by manifest.mf file.
My problem: How can I inject bean references/services to this activator class using Spring as the activator is not configured in Spring context?
Should I not use the OSGI activator? How can Spring startup the application on bundle start?
Any kind of remarks are apreciated as I'm new to OSGI with Spring DM.
Cheers, Sven
You do not need an activator. Spring-DM has an "extender" bundle that automatically scans your bundle for two things:
One or more .xml files in the META-INF/spring folder of your bundle;
A Spring-Context header in your MANIFEST.MF, which points to one or more .xml files that may be anywhere inside your bundle.
If it finds either of these (and if your bundle is in the ACTIVE state) then it will load the Spring application context using the declared XML files.
Related
I am using spring for some dependency injection via the annotations. The problem ist whenever I start the application and use the .jar ,created by gradle, in the classpath Im getting the following exception: "org.springframework.beans.factory.NoSuchBeanDefinitionException"
But if the /build/classes/main/ is in the classpath the beans are created and no exception is thrown.
So the beans are created in the build/classes/main/ but not in the build/libs/*.jar
Set #ComponentScan("classpath*:org.mypackage") to let Spring scan jars as well.
I'm in the process of migrating my project as a spring boot application (mostly for the embedded tomcat solution) from a WAR that was previously deployed on tomcat.
So I encountered a problem with the embedded tomcat container that I hope someone can perhaps offer a solution, perhaps through spring or maven instead of modifying my dependency jars that my project uses to work around this issue.
I have two data model jars that contain xsd files and each one has a catalog file in "/catalog/jaxb-catalog.xml". I found that when one of my libraries call:
Class loader = Thread.currentThread().getContextClassLoader();
URL url = loader.getResource("/catalog/jaxb-catalog.xml");
It would only one xml file and ignore the second xml file as confirmed when i printed out the "url". It seems the container is "TomcatEmbeddedWebappClassLoader" However, when my application is deployed in a standalone tomcat container, the "url" would include both and the container is WebAppClassLoader.
You can read all resources with a name using
org.springframework.core.io.support.PathMatchingResourcePatternResolver
its a normal 'java' class so you can create an instance with new
to find all resources use
resolver.findResources("classpath*:catalog/jaxb-catalog.xml"
have a look at the javadoc of PathMatchingResourcePatternResolver it contains some valuable information.
I am using JBoss AS 7. As i understand, it comes with felix as the ogsi container. I have been using JBoss just as a container for a normal Java EE web application (webapp). However, I've run into so many dependency conflicts, and I'm refactoring some of my code to become bundles (for osgi). My questions are as follows.
Can i access osgi services from my webapp? Note that the webapp will be deployed as normal and not via osgi (it's not a webapp bundle, aka wab). If so, please provide me some links to references on how to do this. I have seen examples the other way around (accessing a webapp from an osgi bundle, but I think the webapp was deployed as a wab).
Is it possible to control the lifecycle of bundles (stop, uninstall, start, install) programmatically from the webapp?
thanks for any help.
Accessing OSGi Services from your webapp is easy.
First u need Dependencies in your MANIFEST.MF, which will be usually deployed
to the webapp/META-INF folder.
Dependencies to add are org.osgi.core and org.jboss.osgi.framework and your deployed Bundles as deployment.yourbundle:version.
Example your bundle is named "yourbundle_1.0.0.1.jar":
Manifest-Version: 1.0
Built-By: me
Build-Jdk: 1.7.0_09
Dependencies: org.osgi.core,org.jboss.osgi.framework,deployment.yourbundle:1.0.0.1
Registering your bundle as a service in the Activator class (should already be done):
public void start(BundleContext bundleContext) throws Exception {
context.registerService(YourBundleService.class.getName(), new YourBundle(),null);
}
Accessing the OSGi BundleContext in JBoss AS needs an EJB:
#Stateless
public class OSGiServiceBean {
#Resource
BundleContext context;
public YourBundleService getBundleService() {
ServiceReference sref = context.getServiceReference(YourBundleService.class.getName());
return (YourBundleService) context.getService(sref);
}
}
if i deploy a war-file into a gemini container (e.g. virgo has one) it will be transformed on-the-fly into an osgi bundle by adding some package imports (besides other things).
Is it possible to somehow extend these default package imports using for example a bundle-listener or something like this?
regards
I would strongly recommend that you do the transformation yourself before deploying into the Gemini container, rather than forcing Gemini to do the transformation on-the-fly. First it is very easy to do; second it will be much faster to deploy; third you will be able to add the specific imports that you want.
In order to turn a standard WAR file into a WAB (Web Application Bundle) that remains compatible with traditional WAR deployment, you just need to add the following headers to the MANIFEST.MF of the WAR:
Web-ContextPath to define the context path under which the web application will be served
Set Bundle-ClassPath to WEB-INF/classes plus any JARs under WEB-INF/lib. You will have to name these explicitly e.g.: Bundle-ClassPath: WEB-INF/classes,WEB-INF/lib/a.jar,WEB-INF/lib/b.jar...
Import-Package: javax.servlet,javax.servlet.http plus anything else you want to import.
I'm developing project with multiple OSGi bundles, deployed on ServiceMix (FuseESB compilation, v. 4.3.1). The issue is, one of this bundles is connecting to EJB on WebLogic, therefore it embeddes weblogic.jar.
The solution is working, however a trick was required. The bundle exports Spring service via OSGi. This service is imported in another bundle, which is entry point to the system. When from this bundle the service was called, the weblogic classes were invisible. The working trick is to wrap Spring service in following aspect, which temporarly switches classloader:
public Object profileInventory(ProceedingJoinPoint pjp) throws Throwable {
Object output = null;
ClassLoader clOld = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(pjp.getTarget().getClass().getClassLoader());
output = pjp.proceed();
} finally {
Thread.currentThread().setContextClassLoader(clOld);
}
return output;
}
As I have understood, the service is called with classloader from entry bundle, not with the classloader from bundle that embedds weblogic, and for this classloader embedded dependency classes are not visible. In similar case, exported Spring service can use private imports and private packages from its bundle, but with embedded jars it is not so.
My question is: is the embedding jars something so specific, that this embedded classes will be visible only when the call originates from embedding bundle (or with classloader swich trick), or there is something more to specify when embedding bundle, something I have forgot to do?
I'm using maven-bundle-plugin
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Bundle-Name>${pom.artifactId}</Bundle-Name>
<Bundle-SymbolicName>${pom.groupId}.${pom.artifactId}</Bundle-SymbolicName>
<Embed-Dependency>
weblogic;scope=*,
</Embed-Dependency>
I have encountered a similar problem when using Spring remoting before. Spring likes to dynamically load classes using the thread context classloader, which doesn't always fare well in OSGi.
The burden to work correctly doesn't belong in the caller though, it belongs in the offending bundle. I don't have the code on hand (it was a couple of years ago), but you need to simply provide the classloader to the Spring remoting classes (I am assuming you are using Spring remoting) to handle the classloading properly.
For example, if the bundle uses SimpleRemoteStatelesSessionProxyFactory, it should be calling the setBeanClassLoader() method.