Import package can not be resolved in maven bundle - java

I am getting problem when tried to start bundle.
Project structure:
--Main project
- sub project 1
- sub project 2
src/main/java/util
- sub project 3
- bundle project 1
- bundle project 2
- bundle project 3
When I compiled main project using Maven install command in eclipse, it's successfully compiled. So, for testing bundle, I have downloaded felix distribution package. I am install bundle successfully but I am not able to start. I getting error dependency cannot be resolved
here is my bundle pom file
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<Export-Package>
com.test.sub_project_3.step,
com.test.sub_project_3.step2
</Export-Package>
<Import-Package>*
org.osgi.framework,
org.osgi.util.tracker,
com.test.sub_project_2.util
</Import-Package>
<Embed-Dependency>
slf4j-api;scope=compile
</Embed-Dependency>
<Bundle-Activator>com.test.sub_project_3.osgi.Activator</Bundle-Activator>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
I am getting error for "com.test.sub_project_2.util cannot be resolved". com.test.sub_project_2 it'sussfully compiled and packag name it's also correct but still I don't understand why I am getting error.

You must understand that OSGi and Maven are different tools with different strategies concerning package resolution.
At design time, maven strategy is used. You indicate your dependency in your POM file. Moreover in your case you used the maven bundle plug in , so you can constrain which package needs to be imported at runtime by your bundle (your import-package section). So in your case, all dependencies are present at design time because your project compiles. But it not implies that the runtime resolution will work, because at runtime OSGi resolution is used.
In your case the error message indicates that your deployed bundle cannot find at runtime the com.test.sub_project_2.util in order to be executed. This is because no bundle present in the OSGi distribution provides the package. So you can bundlify the project that contains the package and deploy it in your OSGi distrib. If you do that the package is now available at runtime.
In a simplistic way you can think as this problem in this way: The classpath used for your bundle is different at design and runtime. And you cannot assume a causality relation between them.
Regards

Related

"cannot be cast to org.osgi.framework.BundleActivator" when declaratively starting OSGi bundle

There's this kind of legacy Spring based java application that runs within a container. I'm trying to provide some OSGi plugin functionality by embedding Apache Felix within this already-existing application. I'm declaratively starting the framework, by following this:
https://dotcms.com/blog/post/navigating-osgi-extending-your-software-to-embed-an-osgi-framework
In case the link doesn't work, what I'm doing is importing Felix as a maven dependency, using the ServiceLoader to get a reference to the framework factory, starting a framework, and loading/starting all bundles in a specific directory.
The bundle is created via the Felix Bundle plugin, with the following configuration:
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>com.example</Export-Package>
<Import-Package>!*</Import-Package>
<Bundle-Name>${project.description}</Bundle-Name>
<Bundle-Activator>com.example.Activator</Bundle-Activator>
<Embed-Transitive>true</Embed-Transitive>
</instructions>
</configuration>
As for the dependencies:
<dependencies>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.framework</artifactId>
<version>6.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
So as you can see, it doesn't import anything (it's the only bundle in the whole application, the servlet itself is not an OSGi bundle). Since the application is not an OSGi bundle, I cannot export the framework classes from it, Felix must be embedded in the bundle itself.
I cannot get the bundle to start. This is what I get (stacktrace has been redacted a bit):
14:43:52,981 ERROR [con.example.Plugin] (Initialization Thread) Failed to start bundle com.example: org.osgi.framework.BundleException: Activator start error in bundle com.example.Plugin[2].
at org.apache.felix.framework.Felix.activateBundle(Felix.java:2448)
at org.apache.felix.framework.Felix.startBundle(Felix.java:2304)
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:998)
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:984)
Caused by: java.lang.ClassCastException: com.example.Activator cannot be cast to org.osgi.framework.BundleActivator
at org.apache.felix.framework.Felix.createBundleActivator(Felix.java:4744)
at org.apache.felix.framework.Felix.activateBundle(Felix.java:2379)
... 35 more
I've managed to reduce this to the possible fact that there are two instances of the BundleActivator interface: one in the bundle's classloader and another one in the Frameworks' ModuleClassLoader. At least I think that's what's going on.
How do people usually work around this? I've tried creating another bundle that just exports the framework for the initial bundle to import, but that one suffers from the same error when it starts. Refactoring the spring app to be overall OSGi capable is out the question (that's why I'm using Felix and not Equinox).
Bundles must not have their own internal copy of the OSGi Framework classes (i.e. the package org.osgi.framework and its subpackages). They must import those packages from the System Bundle.
The cause of the ClassCastException is that in Java the identity of a class is the combination of its fully-qualified name and the ClassLoader that defined it. If you define the BundleActivator type in multiple ClassLoaders — which is what happens when you have copies of it inside bundles — then they are considered different types.
try to change dependency framework scope from compile to provided

How to use OSGI Embed-Dependency for common 3rd party JAR-s

I have a Liferay system with several portlets. Most of these portlets have redundant JSF related JAR-s in them so I would like to remove the redundancy, and create an OSGI bundle for the commonly used JAR-s.
The idea would be that all of my portlets would use this common bundle as a dependency.
After some reading about I ended up with something similar in my maven pom:
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.4</version>
<extensions>true</extensions>
<configuration>
<remoteOBR>true</remoteOBR>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Bundle-Name>${project.name}</Bundle-Name>
<Bundle-Vendor>${project.organization.name}</Bundle-Vendor>
<Import-Package>
!sun.reflect,......,*
</Import-Package>
<Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
</instructions>
</configuration>
</plugin>
And I ended up with the following bundle jar:
My Manifest:
Manifest-Version: 1.0
Bundle-SymbolicName: my-common-bundle
Built-By: pjaloveczki
Bundle-ManifestVersion: 2
Bnd-LastModified: 1537882770915
Embed-Dependency: *;scope=compile|runtime
Import-Package: com.liferay.portal.kernel.exception,com.liferay.portal
.kernel.language,com.liferay.portal.kernel.model,......,org.w3c.dom.styleshe
ets,sun.misc
Tool: Bnd-1.15.0
Bundle-Name: my-common-bundle
Bundle-Version: 1.0.0
Bundle-ClassPath: .,sac-1.3.jar,...all..my..dependecies...,com.liferay.faces.bridge.api-4.1.0.jar
Ignore-Package: net.sf.cglib.proxy,..all..ignored..packages...javax.ejb
Embed-Transitive: true
Created-By: Apache Maven Bundle Plugin
Build-Jdk: 1.8.0_171
Content:
From what I can see, this is exactly what I needed, at least this is how I pictured it.
In my consuming portlet I added the following to my manifest:
Require-Bundle: my-common-bundle;bundle-version="1.0.0"
I figured something like this should work, however I am obviously wrong as when I try to deploy my portlet one of the classes is not being found provided by the common bundle:
java.lang.ClassNotFoundException: org.richfaces.webapp.ResourceServlet cannot be found by MyPortlet
On the other hand if I add the following to my common bundle:
<Export-Package>org.richfaces.webapp</Export-Package>
The class is found, but I am ended up with this:
So essentially I have the class twice once in the JAR and once flattened out, even though it's kind of starting to work.
There are several reason I don't like this approach:
I would prefer using structured jars because I consider it cleaner
Most of these jars contain configuration files that could overlap if I flatten everything out
There must be a way to use embedded jars properly since otherwise this feature would not exist
Can anyone help, what it the proper way to use these embedded jars in an OSGI without having to flatten them out?
Thank!
Peter
EDIT:
It seems that classes are being deployed fine and are resolved after I've added
<_exportcontents>!org.apache.commons.logging,*</_exportcontents>
however I am getting different types of errors which I am not getting when I put my JARs in my portlets.
Previously I was getting ClassNotFoundErrors and such, now I am getting:
java.lang.NullPointerException
at javax.faces.CurrentThreadToServletContext.getFallbackFactory(CurrentThreadToServletContext.java:79)
at javax.faces.FactoryFinderInstance.getFactory(FactoryFinderInstance.java:551)
at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:283)
at javax.faces.webapp.FacesServlet.init(FacesServlet.java:358)
java.lang.NullPointerException
at javax.portlet.faces.GenericFacesPortlet.getBridgeClassName(GenericFacesPortlet.java:193)
at javax.portlet.faces.GenericFacesPortlet.getBridge(GenericFacesPortlet.java:762)
at javax.portlet.faces.GenericFacesPortlet.init(GenericFacesPortlet.java:448)
at com.liferay.portlet.InvokerPortletImpl.init(InvokerPortletImpl.java:297)
It seems to me classes are loaded, but the JAR manifests are not being processed or something similar. Any ideas?
you can use <_exportcontents> instruction to export the content without duplication, more about it here
I would like to point out that creating fat jars is against the very idea of OSGi, also, this is going to be a nightmare to maintain when your code evolves.
Ideally you would want to have a separate bundle for each dependency. They should be deployed and maintained separately.

eclipse: external CDI in EJB module: NoClassDefFoundError

My current project consisting of a war and ejb module, is using a jar (incorperated via maven). This jar contains a CDI component which, when I inject this in the war module it works as expected, but when I inject this in my ejb module I get a NoClassDefFoundError during startup from my WAS 8.5 in eclipse (full profile).
When I start the server first, add the inject later and republish it seems to work. Also when I use Liberty profile it works. Also on Z/os and IPAS it works as expected.
I think it might has something todo with classloading, but have no idea how to solve this properly.
Using Eclipse Neon, WAS 8.5.5.11 full profile , jee6
Project is using java 8 while the component is using java 6
This is the first part of the stacktrace:
[13-9-17 14:54:26:589 CEST] 0000003e InjectionProc W CWNEN0047W: Resource annotations on the fields of the BestelFacade class will be ignored. The annotations could not be obtained because of the exc
eption : Logger
at java.lang.Class.getDeclaredFieldsImpl(Native Method)
Thanks
I found a way to get the job done, but I'm not sure if this is a proper solution or just a workaround while masking the real problem.
When I take a look at the ear module assembly I see in the source column c:/ws/.../jar and in the deploy path lib/jar
when I change the source into /..ear/target/../jar it works
Try setting the <bundleDir>/</bundleDir>
This will place the external jar/ejb not in lib, but in the root.
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<configuration>
...........
<defaultLibBundleDir>lib</defaultLibBundleDir>
<modules>
<jarModule>
<groupId>groupId</groupId>
<artifactId>artifactId</artifactId>
<bundleDir>/</bundleDir>
</jarModule>
</modules>
</configuration>
</plugin>

Felix OSGI Embedded application issue

I was using Felix as a embedded application as explained in,
How to start and use Apache Felix from code?. What I want to do is dynamically load jar files from my host application via OSGi and invoke methods of implementation classes.
So I have following three maven projects
1) A maven project which has an interface. And the package of this interface is exported. ---> ProjA .
2) A implementation project --> ProjB, another maven project which import ProjA as a maven dependency and implement interface on it with a concrete class. Also in this project I do OSGi import-package for ProjA interface package. Also here I register my implementation on OSGI via activator.
3) Then ProjC which is the hosted application. What I do there is,
HostActivator activator = new HostActivator();
List<Object> list = new LinkedList<Object>();
list.add(activator);
map.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, list);
Felix f = new Felix(map);
f.start();
Bundle a = f.getBundleContext().installBundle("file:C:/ProjA.jar");
Bundle b = f.getBundleContext().installBundle("file:C:/ProjB.jar"); ); // dirty path ;)
b.start();
ServiceReference sr = activator.getContext().getAllServiceReferences(MyInterface.class.getName(), "(" + "osgi-device-name" + "=*)")[0];
MyInterface dictionary = (MyInterface) activator.getContext().getService(sr);
dictionary.doAction();
Everything works fine until cast. There I can see following error,
Exception in thread "main" java.lang.ClassCastException: projB.MyImplementation cannot be cast to projA.MyInterface
at MyHostApplication.MyMainClass.main(MyMainClass.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Can anyone help me on this, for me this seems like a bug on felix.
ProjA is on the classpath of your main project (that opens the embedded OSGi container) and it is also installed into the embedded OSGi container as a bundle. When ProjB is resolved, it wires to the ProjA bundle, so it implements the interface that is coming from the installed projA bundle.
When you try to cast the result object, you try to cast to the interface that is on the classpath of the main project. That is a different interface that the ProjB bundle implements as it implements the interface from projA bundle.
You should not install ProjA as a bundle into the OSGi container. You should be sure that ProjB bundle can resolve. To do that, you should add projA as a system package to the embedded OSGi container.
another way to solve this problem is using export tag in maven maven-bundle-plugin or manifest file
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
<Export-Package>come.example.myInterface</Export-Package>
<Bundle-Activator>come.example.Activator</Bundle-Activator>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
and did'nt forget
map.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "come.example.myInterface; version=0.0.1");

Error deploying third party jar files in karaf

I am trying to deploy a bundle in apache-karaf 3.0.3 which contains certain number of third party jar files which i am embedding inside,
since the third party jar files are non OSGi bundles. Out of which one jar file contains an import statement in a java file which doesn't exist
anymore in the latest version of jar file.(I didn't have the olderversion of jar file).
e.g: jar file 1
- Class1
- import com.java.test.io
While deploying my application bundle with the jar files i am facing an error.
Error executing command: Error executing command on bundles:
Unable to execute command on bundle 391: The bundle "com.test.example.bundle_0.1.0.SNAPSHOT [391]" could not be resolved.
Reason: Missing Constraint: Import-Package: com.java.test.io; version="0.0.0"
I am trying to replicate the scenario with simple java application, it works as expected.
My assumption is that karaf will scan all the import statements and check whether there is a proper export package(package level permission)
exists for the appropriate import statment.
Can anybody explain why java application runs and in karaf it fails?
pom.xml
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>mybundlename</Bundle-SymbolicName>
<Embed-Dependency>jar1,jar2,jar3,jar4</Embed-Dependency>
</instructions>
</configuration>
</plugin>
</plugins>
What matters is not the package import in your class but the package import in your bundle's MANIFEST.
If your code works outside of an OSGi container, then it means that the imported package is not required at runtime in your particular usage scenario. Or it is not required at all and should be cleaned up.
You either have to deploy a bundle to satisfy the import or you have to suppress the addition of the import of com.java.test.io when building your bundle. With the maven-bundle-plugin you can achieve this like so:
<instructions>
<Embed-Dependency>...</Embed-Dependency>
<Import-Package>
!com.java.test.io.*,
*
</Import-Package>
</instructions>

Categories

Resources