I have an OSGi bundle (deployed into Karaf 2.2.4) that starts a Camel (2.10.0) context. The Camel context's routebuilder has some xquery endpoint URIs such as
"xquery:classpath:Dir1/Dir2/example.xq"
When the context tried to resolve that URI, it failed since the Camel bundle is not in the same classpath as where the .xq file resides. So, I created a url expand function that turns
"xquery:classpath:..."
into
"xquery:bundle://42.0:6/..."
since I had dealt with bundle URIs and the OsgiBundleResourcePatternResolver earlier in my project when dealing with a ClassPathScanningCandidateComponentProvider (Spring 3.1.1). Unfortunately, I can't seem to find a way to make Camel's XQueryComponent use my OsgiBundleResourcePatternResolver.
Am I going about this the right way? Is there an easier way to do this?
If I am, how can I make sure the XQueryComponent can understand a bundle: URI?
Also, is it possible for me to make sure any camel component can understand a bundle: URI?
You application that has the Camel route with the above xquery endpoint, would need to import the package where the xq file is located, eg the package that represents "Dir1.Dir2".
So in the META-INF/MANIFEST.MF which has the OSGi imports|exports. You should have an import for that given package.
And to answer your 3 bullets
No, see above
You would need to extend this component and add your own logic for the "bundle"
No, not really, as you would need to add logic to camel-core/camel-core-osgi.
Also the bundle id of an application can change, so its not advised to refer to a bundle by its id. And you cannot assign the bundle id, that is self assigned by the osgi container.
Thanks to Claus' answer, I was able to realize that my .xq file was not in the right directory in its .jar.
Dir1 resided in root of its .jar file. While running the application in a non-OSGi web container worked fine, Karaf appears to be more strict regarding where resources should be in my .war file. I moved the .xq files to WEB-INF/classes/Dir1/... and now am no longer receiving FileNotFoundExceptions when the code uses xquery:classpath:Dir1/Dir2/example.xq
Related
While migrating existing spring project to osgi karaf, we are facing the problem while import resource from the dependent bundle.Eg.
Bundle A has the appcontxt-A.xml and Bundle B which has appcontext-B.xml.
Here I am referring appcontxt-A.xml in Bundle B as (<import resource="classpath:appContext-A.xml" />) for which I am getting Caused by: java.io.FileNotFoundException: class path resource [appContext-A.xml] cannot be opened because it does not exist.
How I can achieve the above defined scenario.Thanks in advance.
It is not entirely clear to me how exactly you attempt to access the appContext-A.xml resource since you have not included any code samples, however keep in mind that in OSGi bundles A and B have different classloaders and therefore you will not be able to get a resource of bundle A directly from bundle B. What you can do is get a reference to bundle A through the BundleContext and get the resource you need from there. Something like the following:
bundleContext.getBundle(bundleA).getResource(resource)
After long research resolved the file doesnt exist issue was resolved by (adding * after classpath) . However while accessing "context:annotation-config" there is another issue Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/context], Any help to resolve this issue?
With the further added information it's clear, you'll need to make sure that bundle A does actually export the resource, and be does actually import it.
Additionally you'll need to make sure you retrieve that resource as Christina said.
If you are using a Spring based approach, make sure you have Spring-DM also available.
I have two OSGi bundles A and B. Both are created with the API/implementation model. Both the bundles are activated through Blueprint mechanism. Both the API bundles export the interfaces whereas the implementation bundles don't export anything. Only A has dependency on B.
My issue is, I want to pass a resource file name (xml file) that resides in bundle A to Bundle B (after I get hold of B using the BundleContext.getServiceReferences() method) and then load the resource in Bundle B and process it. How can I achieve the same and is it even doable?
I read the following post and Neil Bartlett's answer suggest it should work.
Access resources in another osgi bundle?
However, when I read about getEntry, findEntries, getEntrypath methods, they don't talk about other bundles (or I misunderstood it). They talk only about fragments.
My question is, can I achieve what I am looking for using any of the above three methods? If so, can you please point to some other thread that has the answers or some sample code?
If this is not possible, can I use fragment bundles(containing only resources)? Again Bundle B is more like a provider where it can take any resource file and process it and satisfy clients requests (Bundle A). So even if I want to use bundle fragment approach, I need B to load the fragment bundle (only on needed basis) specified by clients (say they give the fragment bundle symbolic name). Please provide suggestions or other posts related to similar issues or any samples.
The easiest way to access a resource in a bundle is to use the classLoader of the bundle. In bundle A you get service MyService and do:
InputStream is = this.getClass().getResourceAsStream("myresource.xml");
MyService service.doSomething(is);
or if you prefer a URL:
URL url = this.getClass().getResource("myresource.xml");
MyService service.doSomething(url);
This works as we already resolve the resource before making the call. If you want to give the service just a relative path then you additionally need to give it the classLoader to get the resource from.
ClassLoader bundleALoader = this.getClass().getClassLoader();
MyService service.doSomething(bundleALoader, "myresource.xml");
Keep in mind though that this.getResource() will lookup the resource relatively to the package of "this" while classLoder.getResource() will lookup from the top of the name space.
Btw. These concepts also work fine outside of OSGi. The difference is only that in OSGi you have to make sure to use the classLoader that has visibility of a resource while outside there is often only one classLoader that sees all resources.
In a specific point in my deployed OSGi bundle, I get a jar file URI in OSGi standard format, jar file that I need to parse for entity classes. So, having the URI like: bundle://233.0:1, would it be possible to get the jar file so that, I will be able to parse it for what kind of entity it has?
Note: I'm trying to solve an issue that I have with OpenJPA, Apache Servicemix and Spring Framework.
If you need any further clarifications, ask me please.
You do not need the jar. You can query the entries of a bundle with the following functions:
http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/Bundle.html#findEntries(java.lang.String,%20java.lang.String,%20boolean)
http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/wiring/BundleWiring.html#findEntries(java.lang.String,%20java.lang.String,%20int)
http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/wiring/BundleWiring.html#listResources(java.lang.String,%20java.lang.String,%20int)
First one returns only entries that is available in the bundle directly. Second one returns entries from the bundle and its fragments. Third one returns entries that the bundle's classloader sees (entries of the bundle, its fragments and entries from imported packages)
I'm having a problem I simply can't get my head around.
I'm creating a jsf application where I (as administrator) can upload a jar file, and that way around update the application.
Through this tutorial: http://docs.oracle.com/javase/tutorial/deployment/jar/jarclassloader.html I have managed to classload the jar file. The first issue is that I can only class load as "Object" and not cast to an other class type. I get a ClassCastException.
JarClassLoader jcl=new JarClassLoader(url);
Class cl= jcl.retreiveClass(jcl.getMainClassName());
Object ob=cl.newInstance(); //I would like to make this a RouteBuilder object instead of Object
Concretely I'm using Apache Camel, where I can add routes to an existing "core" (CamelContext). What's happening is that I have the core of apache camel running in my web app, and I can then add routes runtime. It's a route I want to package as a jar and load into the app runtime (I want to develop and test the route in my local environment, and then afterwords upload it to the production application). A concrete route is just a simple java class that extends RouteBuilder. I want to upload the jar, classLoad (URLClassLoader) the main class (maybe the whole jar? - does that make sense?), and convert it to a RouteBuilder. This seems to be impossible. I have chosen to upload the jar file to a folder outside my war, so that the routes do not get erased when I restart the webapp (is this smart or should this be done in an other way?). Is that a problem regarding name spaces? Furthermore, I haven't been able to find out whether I need to traverse my entire jar file and classload ever single class inside. Any comments on that?
To me it seems like I have some fundamental misconceptions on how extending / updating a java application is done. I simply can't find any good examples/explanations on how to solve my problem and therefore I conclude that I don't get this on a conceptual level.
Could someone elaborate on how to extend a running jsf application (I guess the same issues are relevant in native java apps), explain how to upload and class load a jar at runtime, and how to cast loaded classes to other class types than Object?
Thanks
Lasse
If you are interested in loading Routes without stopping your application you could consider using an OSGi container like Karaf. Karaf provides support for Apache Camel routes out-of-the-box: http://camel.apache.org/karaf.html
All class loading is managed by the OSGi container and you just need to run some commands to update things. I am not sure if this could work with your JSF application but it worths to take a look.
I am facing the following issue: I am developing an OSGi bundle with Spring and I would like to allow the developers who will use my bundle to add a Spring context file through a fragment.
These files will be use to configure my Spring beans (a similar existing example without Spring: configuration file in a fragment for org.apache.log4j).
I have to use the Spring framework for several reasons that are out of the scope of this question, but I can't use the following directive
<import resource="..."/>
because I am not even sure that some fragment will be available at run time (it being optional configuration), and I know that Spring will complain if it is unable to find the resource. Ideally, I would like to have something like this:
<import resource="my_default_configuration.xml"/>
<import resource="my_extended_configuration.xml"
doesNotComplainIfAbsent="true"
override="true"/>
Do you have any ideas to help me?
Thanks in advance.
I think using OSGi properly would be a better way of doing it. Spring DM (AKA Gemini Blueprint) allows you to import and export Spring beans via OSGi. So your bundle could attempt to import all beans matching a specific interface, which developers using your bundle would export from their own bundle. It would still be optional, because you would end up with an empty list in your bundle if the developer chose not to provide any.