I am writing a karaf bundle which depends on an external jar library. I understand I may import this bundle in my features.xml using wrap but this means it gets loaded into its own classloader.
What I want is for my bundle's classloader to load whatever I access in this jar file and I want to make direct method calls to the classes in this jar file. How can I do this?
I don't want a new bundle - just a library that I can link my application to.
Thanks,
You can try to embed the external jar when building your bundle as follow:
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>
...,
root_package_in_external_jar*,
...
</Export-Package>
<Import-Package>
...
</Import-Package>
<Embed-Dependency>your_external_jar</Embed-Dependency>
</instructions>
</configuration>
</plugin>
I'm suceeded with adding OSGi specific meta-data to the MANIFEST of the flying-saucer-pdf Maven artifact. However, I do not succeed with embedding the dependencies and transitive dependencies of that artifact into the created JAR file.
I was using the original sources from flying-saucer-pdf taken from GitHub [1] and added the following statements to the pom.xml file:
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Embed-Dependency>itext</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
</instructions>
</configuration>
</execution>
</executions>
</plugin>
The artifact has a dependency declared to itext version 2.1.7 in its original pom.xml which I did not touch. I also did not mess with the original packaging type of the artifact which is jar.
Unfortunately, this does only part of the work. The MANIFEST.MF seems correct and contains the expected OSGi tags:
Manifest-Version: 1.0
Bundle-Description: Flying Saucer is a CSS 2.1 renderer written in Jav
a. This artifact supports PDF output.
Bundle-License: http://www.gnu.org/licenses/lgpl.html
Bundle-SymbolicName: org.xhtmlrenderer.flying-saucer-pdf
Archiver-Version: Plexus Archiver
Built-By: u0400072
Bnd-LastModified: 1478168053263
Bundle-ManifestVersion: 2
Embed-Dependency: itext
Import-Package: com.apple.mrj,com.lowagie.toolbox,javax.crypto,javax.i
mageio,javax.imageio.metadata,javax.imageio.plugins.jpeg,javax.imagei
o.stream,javax.swing,javax.xml.parsers,javax.xml.transform,javax.xml.
transform.dom,javax.xml.transform.sax,javax.xml.transform.stream,org.
bouncycastle.asn1,org.bouncycastle.asn1.cmp,org.bouncycastle.asn1.cms
,org.bouncycastle.asn1.ocsp,org.bouncycastle.asn1.pkcs,org.bouncycast
le.asn1.tsp,org.bouncycastle.asn1.x509,org.bouncycastle.cms,org.bounc
ycastle.crypto,org.bouncycastle.crypto.engines,org.bouncycastle.crypt
o.modes,org.bouncycastle.crypto.paddings,org.bouncycastle.crypto.para
ms,org.bouncycastle.jce.provider,org.bouncycastle.ocsp,org.bouncycast
le.tsp,org.w3c.dom,org.xhtmlrenderer.context,org.xhtmlrenderer.css.co
nstants,org.xhtmlrenderer.css.extend,org.xhtmlrenderer.css.parser,org
.xhtmlrenderer.css.sheet,org.xhtmlrenderer.css.style,org.xhtmlrendere
r.css.style.derived,org.xhtmlrenderer.css.value,org.xhtmlrenderer.ext
end,org.xhtmlrenderer.layout,org.xhtmlrenderer.render,org.xhtmlrender
er.resource,org.xhtmlrenderer.simple.extend,org.xhtmlrenderer.swing,o
rg.xhtmlrenderer.util,org.xml.sax,org.xml.sax.helpers
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.6))"
Tool: Bnd-3.2.0.201605172007
Embedded-Artifacts: itext-2.1.7.jar;g="com.lowagie";a="itext";v="2.1.7
"
Export-Package: org.xhtmlrenderer.pdf;uses:="org.w3c.dom,org.xhtmlrend
erer.css.constants,org.xhtmlrenderer.css.parser,org.xhtmlrenderer.css
.style,org.xhtmlrenderer.css.value,org.xhtmlrenderer.extend,org.xhtml
renderer.layout,org.xhtmlrenderer.render,org.xhtmlrenderer.resource,o
rg.xhtmlrenderer.simple.extend,org.xhtmlrenderer.swing,org.xml.sax";v
ersion="9.0.10",org.xhtmlrenderer.pdf.util;uses:="org.w3c.dom,org.xht
mlrenderer.pdf";version="9.0.10",org.xhtmlrenderer.simple;uses:="java
x.swing,org.w3c.dom,org.xhtmlrenderer.css.extend,org.xhtmlrenderer.cs
s.sheet,org.xhtmlrenderer.extend,org.xhtmlrenderer.layout,org.xhtmlre
nderer.swing,org.xhtmlrenderer.util";version="9.0.10"
Bundle-Name: Flying Saucer PDF Rendering
Bundle-Version: 9.0.10.SNAPSHOT
Bundle-ClassPath: .,itext-2.1.7.jar
Embed-Transitive: true
Created-By: Apache Maven Bundle Plugin
Build-Jdk: 1.8.0_102
But the itext library is not put into the resulting JAR, i.e. the Bundle-ClassPath entry of the MANIFEST points to a missing content.
In addition I tried to create an entirely new artifact which declares a dependency to the original flying-saucer-pdf artifact and re-bundles it as an OSGi bundle flowing this answer [2] here on StackOverflow and this worked.
The only real difference that I can see is the packaging type 'bundle' vs. 'jar'. But I cannot change that packaging type in the original flying-saucer-pdf artifact since everything needs to stay as is for non-OSGi-usages in order to get that change accepted as a Push Request.
Do you guys know if this embedding dependencies with the maven-bundle-plugin can actually work with the packaging type 'jar'? Or does it need the packaging type 'bundle'?
I appreciate any response and hint of what I could try to get that re-bundling done directly within the original artifact.
Thank you very much.
Regards
Timo Rohrberg
There are two ways to use the maven bundle plugin.
The first way is to use
<extensions>true</extensions> and <packaging>bundle</packaging>
In this case the maven bundle plugin is in charge of all build steps and can influence the jar file contents.
The second way is to use the manifest goal and add the manifest in the jar plugin. In this case maven bundle plugin can only influence the jar. It can not embed any other library or copy over external private classes.
So if you need embedding then the only way is to change the packaging.
So I think there are two solutions that do not influence the original jar too much.
Do not embed and install the dependencies as bundles
Create a spearate module in the build to create a bundle that is then available additionally to the original jar
ServiceMix's documentation on creating a custom distribution merely states the steps to creating a custom karaf distribution. I understand that Karaf is the backbone of ServiceMix and ServiceMix is a custom distribution of Karaf.
Has anyone actually built a custom esb on top of servicemix rather than on top of karaf? If so how did you do it?
How did you stage the project with servicemix's src?
Here are some steps that I wish I had when trying to figure this out...
Download the sources for the version of service mix you want to build on: https://github.com/apache/servicemix/releases
Unpack the sources zip into any folder.
Create a project with the following layout:
MyESB
pom.xml
src
main
java
Copy the contents from the pom.xml located in apache-service-mix-x.x.x-src/assembly to your pom.xml
In that pom.xml, replace the artifactId, and name to look something like this:
<parent>
<groupId>org.apache.servicemix</groupId>
<artifactId>parent</artifactId>
<version>5.4.0</version>
</parent>
<groupId>com.mycompany.esb</groupId>
<artifactId>mycustom-esb</artifactId>
<packaging>pom</packaging>
<name>Custom :: ESB</name>
Copy the resource directories of apache-service-mix-x.x.x-src/assembly/src/main to MyESB/src/main.
Make whatever customizations you want to the org.apache.karaf.tooling:features-maven-plugin or the configuratoin files in the resource directories you just copied over.
For example, If you wanted to add a particular feature you could do the following edits to your pom.xml:
Add a features.xml to add-features-to-repo configuration descriptors
Add myfeature to the add-features-to-repo features list
To have that feature started by default, add the feature to the featuresBoot property located here: MyESB\src\main\filtered-resources\etc\org.apache.karaf.features.cfg
Run the maven install target! This will build a zip file into the MyESB/target folder. Now you can unplack that and run servicemix.bat
After starting your ESB, verify that your feature is installed by entering the following command into the Karaf console:
features:list | grep myfeature
Well, just do it like servicemix itself it does. And tbh it's just the way it's described in the Karaf documentation.
For an example you might want to look here
In short define it in your custom assembly POM, take a look at the following snippet:
<plugins>
<plugin>
<groupId>org.apache.karaf.tooling</groupId>
<artifactId>karaf-maven-plugin</artifactId>
<version>${karaf.version}</version>
<executions>
<execution>
<id>add-features-to-repo</id>
<phase>compile</phase>
<goals>
<goal>features-add-to-repository</goal>
</goals>
<configuration>
<descriptors>
<descriptor>mvn:org.apache.karaf.features/standard/${karaf.version}/xml/features</descriptor>
<descriptor>mvn:org.apache.karaf.features/enterprise/${karaf.version}/xml/features</descriptor>
<descriptor>mvn:org.apache.karaf.features/spring/${karaf.version}/xml/features</descriptor>
<descriptor>mvn:org.apache.activemq/activemq-karaf/${activemq.version}/xml/features</descriptor>
<descriptor>mvn:org.apache.camel.karaf/apache-camel/${camel.version}/xml/features</descriptor>
<descriptor>mvn:org.apache.cxf.karaf/apache-cxf/${cxf.version}/xml/features</descriptor>
<descriptor>file:${basedir}/target/classes/internal.xml</descriptor>
<descriptor>file:${basedir}/target/classes/features.xml</descriptor>
<descriptor>file:${basedir}/target/classes/examples.xml</descriptor>
</descriptors>
<features>
<feature>cxf</feature>
<feature>obr</feature>
<feature>config</feature>
<feature>standard</feature>
<feature>package</feature>
<feature>kar</feature>
<feature>ssh</feature>
<feature>management</feature>
<feature>eventadmin</feature>
<feature>activemq-broker-noweb</feature>
<feature>activemq-service</feature>
<feature>camel</feature>
<feature>camel-cxf</feature>
<feature>activemq-camel</feature>
<feature>camel-blueprint</feature>
<feature>war</feature>
<feature>jaxrs-api</feature>
</features>
<includeMvnBasedDescriptors>true</includeMvnBasedDescriptors>
<repository>target/features-repo</repository>
</configuration>
<inherited>false</inherited>
</execution>
</executions>
</plugin>
If you need your own custom bundles/features make sure you
a) have a feature descriptor for your own bundles
b) define the feature descriptor
c) tell the plugin to use the corresponding feature
I am using the maven-feature-plugin
<plugin>
<groupId>org.apache.karaf.tooling</groupId>
<artifactId>features-maven-plugin</artifactId>
<version>2.3.6</version>
<executions>
<execution>
<id>generate</id>
<phase>generate-resources</phase>
<goals>
<goal>generate-features-xml</goal>
</goals>
<configuration>
<bundles>src/main/resources/bundle.properties</bundles>
<kernelVersion>2.3.6</kernelVersion>
<outputFile>target/features.xml</outputFile>
</configuration>
</execution>
</executions>
</plugin>
This works pretty well but one of my generated features depends on the pax-cdi feature is there a way for me to get the plugin to add this for me? For example I have some dependencies defined in the bundle.properties file that cannot be resolved automatically, could I add a feature in this file as well?
You can add the feature as a maven dependency in your pom:
<dependency>
<groupId>org.ops4j.pax.cdi</groupId>
<artifactId>pax-cdi-features</artifactId>
<version>0.8.0</version>
<classifier>features</classifier>
<type>xml</type>
</dependency>
This will result a feature.xml containing the pax-cdi features (providing that karaf-maven-plugin is configured with <aggregateFeatures>true</aggregateFeatures>).
You can also leave it to the container to pull in the pax-cdi feature. Just edit $KARAF_HOME/etc/org.apache.karaf.features.cfg where you can enlist your pax-cdi-features by adding the maven url to the list of featuresRepositories.
featuresRepositories=....
....,\
mvn:org.ops4j.pax.cdi/pax-cdi-features/0.8.0/xml/features
Then add pax-cdi to the list of boot features
featuresBoot=.....,pax-cdi,...
Karaf will start the bundles of pax-cdi when it boots, so that your bundles can find those cdi packages available.
I think that the karaf convention is that the pax-cdi feature should be provided by the container itself, so you don't need to add those bundles to your feature descriptor.
To use pax-cdi feature in karaf enter the following in your Karaf shell
features:addurl mvn:org.ops4j.pax.cdi/pax-cdi-features/0.8.0/xml/features
I need to consume a web service in my project. I use NetBeans so I right-clicked on my project and tried to add a new "Web Service Client". Last time I checked, this was the way to create a web service client. But it resulted in an AssertionError, saying:
java.lang.AssertionError: org.xml.sax.SAXParseException; systemId: jar:file:/path/to/glassfish/modules/jaxb-osgi.jar!/com/sun/tools/xjc/reader/xmlschema/bindinfo/binding.xsd; lineNumber: 52; columnNumber: 88; schema_reference: Failed to read schema document 'xjc.xsd', because 'file' access is not allowed due to restriction set by the accessExternalSchema property.
The default Java platform for NetBeans was JDK8 (Oracle's official version), so when I changed my netbeans.conf file and made JDK7 (from Oracle, as well) as my default, everything worked fine. So I think the problem is with JDK8. Here is my java -version output:
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)
For now, I'm keeping JDK7 as my default Java platform. If there is a way to make JDK8 work please share.
Well, I found the solution. (based on http://docs.oracle.com/javase/7/docs/api/javax/xml/XMLConstants.html#ACCESS_EXTERNAL_SCHEMA)
Create a file named jaxp.properties (if it doesn't exist) under /path/to/jdk1.8.0/jre/lib and then write this line in it:
javax.xml.accessExternalSchema = all
That's all. Enjoy JDK 8.
Not an actual answer but more as a reference.
If you are using the jaxws Maven plugin and you get the same error message, add the mentioned property to the plugin configuration:
...
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3</version>
<configuration>
<!-- Needed with JAXP 1.5 -->
<vmArgs>
<vmArg>-Djavax.xml.accessExternalSchema=all</vmArg>
</vmArgs>
</configuration>
</plugin>
I run ant builds within Eclipse IDE (4.4, Luna, on Windows 7 x64). Rather than modifying the installed JRE lib or any ant scripts (I have multiple projects that include XJC in their builds), I prefer to change Eclipse Settings "External Tools Configurations" and add the following to the VM arguments for the Ant build configuration:
-Djavax.xml.accessExternalSchema=all
The following works for wsimport 2.2.9 included in jdk 1.8.0_66:
wsimport -J-Djavax.xml.accessExternalSchema=all ....
In my case adding:
javax.xml.accessExternalSchema = all
to jaxp.properties didn't work, I've to add:
javax.xml.accessExternalDTD = all
My environment is linux mint 17 and java 8 oracle.
I'll put it there as an answer for people with the same problem.
I tested this for version 2.4 of artifact org.codehaus.mojo and that worked ~
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<wsdlDirectory>path/to/dir/wsdl</wsdlDirectory>
</configuration>
<id>wsimport-web-service</id>
<phase>generate-sources</phase>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>webservices-api</artifactId>
<version>${webservices-api-version}</version>
</dependency>
</dependencies>
<configuration>
<vmArgs>
<vmArg>-Djavax.xml.accessExternalSchema=all</vmArg>
</vmArgs>
<sourceDestDir>generated-sources/jaxws-wsimport</sourceDestDir>
<xnocompile>true</xnocompile>
<verbose>true</verbose>
<extension>true</extension>
<sei>/</sei>
</configuration>
</plugin>
</plugins>
Here is a hint Hint for gradle users without admin rights: add this line to your jaxb-task:
System.setProperty('javax.xml.accessExternalSchema', 'all')
it will look like this:
jaxb {
System.setProperty('javax.xml.accessExternalSchema', 'all')
xsdDir = "${project.name}/xsd"
xjc {
taskClassname = "com.sun.tools.xjc.XJCTask"
args = ["-npa", "-no-header"]
}
}
If you are getting this problem when converting wsdl to jave with the cxf-codegen-plugin, then you can solve it by configuring the plugin to fork and provide the additional "-Djavax.xml.accessExternalSchema=all" JVM option.
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<fork>always</fork>
<additionalJvmArgs>
-Djavax.xml.accessExternalSchema=all
</additionalJvmArgs>
I was also getting similar type of error in Eclipse during testing a webservice program on glassfish 4.0 web server:
java.lang.AssertionError: org.xml.sax.SAXParseException; systemId: bundle://158.0:1/com/sun/tools/xjc/reader/xmlschema/bindinfo/binding.xsd; lineNumber: 52; columnNumber: 88; schema_reference: Failed to read schema document 'xjc.xsd', because 'bundle' access is not allowed due to restriction set by the accessExternalSchema property.
I have added javax.xml.accessExternalSchema = All in jaxp.properties, but doesnot work for me.
However I found a solution here below which work for me:
For GlassFish Server, I need to modify the domain.xml of the GlassFish,
path :<path>/glassfish/domains/domain1 or domain2/config/domain.xml) and add, <jvm-options>-Djavax.xml.accessExternalSchema=all</jvm-options>under the <java-config> tag
....
<java-config>
...
<jvm-options>-Djavax.xml.accessExternalSchema=all</jvm-options>
</java-config>
...and then restart the GlassFish server
Enabling Access to External Schema
You need to enable the IDE and the GlassFish Server to access external schema to parse the WSDL file of the web service. To enable access you need to modify the configuration files of the IDE and the GlassFish Server. For more details, see the FAQ How to enable parsing of WSDL with an external schema?
Configuring the IDE
To generate a web service client in the IDE from a web service or WSDL file you need to modify the IDE configuration file (netbeans.conf) to add the following switch to netbeans_default_options.
-J-Djavax.xml.accessExternalSchema=all
For more about locating and modifying the netbeans.conf configuration file, see Netbeans Conf FAQ.
Configuring the GlassFish Server
If you are deploying to the GlassFish Server you need to modify the configuration file of the GlassFish Server (domain.xml) to enable the server to access external schemas to parse the wsdl file and generate the test client. To enable access to external schemas, open the GlassFish configuration file (GLASSFISH_INSTALL/glassfish/domains/domain1/config/domain.xml) and add the following JVM option element (in bold). You will need to restart the server for the change to take effect.
</java-config>
...
<jvm-options>-Djavax.xml.accessExternalSchema=all</jvm-options>
</java-config>
Create a file named jaxp.properties (if it doesn’t exist) under path to your "JDK version/jre/lib" and then add the following line in it.
javax.xml.accessExternalSchema = all
When using Maven with IntelliJ IDE you can add -Djavax.xml.accessExternalSchema=all to Maven setting under JVM Options for Maven Build Tools Runner configuration
This works on jdk1.8.0_65
wsimport -J-Djavax.xml.accessExternalSchema=all -keep -verbose https://your webservice url?wsdl
For those using the ANT task wsimport, a way of passing the option as suggested by #CMFly and specified in the documentation is the following:
<wsimport
<!-- ... -->
fork="true"
>
<jvmarg value="-Djavax.xml.accessExternalSchema=all"/>
</wsimport>
It is now fixed in 2.5 version (released in jul/17). https://github.com/mojohaus/jaxws-maven-plugin/issues/8.
For the 2.4.x versions there is a workaround (as decribed in https://github.com/mojohaus/jaxws-maven-plugin/issues/4):
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.4.1</version>
<dependencies>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-tools</artifactId>
<version>2.2.10</version>
</dependency>
</dependencies>
</plugin>
I used it with a regular maven project, and got it solved with this plugin dependency configuration for running the xjc plugin:
<plugin>
<!-- Needed to run the plugin xjc en Java 8 or superior -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<id>set-additional-system-properties</id>
<goals>
<goal>set-system-properties</goal>
</goals>
</execution>
</executions>
<configuration>
<properties>
<property>
<name>javax.xml.accessExternalSchema</name>
<value>all</value>
</property>
<property>
<name>javax.xml.accessExternalDTD</name>
<value>all</value>
</property>
</properties>
</configuration>
</plugin>
Another solution to address: wiki.netbeans.org
The Web Service Client wizard in the IDE parses the WSDL file when generating a web service client from a web service or WSDL file. You need to modify the IDE configuration file (netbeans.conf) to add the following switch to the netbeans_default_options. You will need to restart the IDE for the change to take effect.
-J-Djavax.xml.accessExternalSchema=all
When deploying to GlassFish you need to enable access to external schema to generate a test client for a web service. To enable access you need to modify the configuration file of the GlassFish Server (GLASSFISH_INSTALL/glassfish/domains/domain1/config/domain.xml) and add the following JVM option element. You will need to restart the server for the change to take effect.
</java-config>
...
<jvm-options>-Djavax.xml.accessExternalSchema=all</jvm-options>
</java-config>
I have just tried that if you use SoapUI (5.4.x) and use Apache CXF tool to generate java code, put javax.xml.accessExternalSchema = all in YOUR_JDK/jre/lib/jaxp.properties file also works.
If you are using ant you can add a jvmarg to your java calls:
<jvmarg value="-Djavax.xml.accessExternalSchema=all" />
Another alternative is to update wsimport.sh shell script by adding the following:
The wsimport.sh is located in this directory:
jaxws-ri.2.2.28/bin
exec "$JAVA" $WSIMPORT_OPTS -Djavax.xml.accessExternalSchema=all -jar "$JAXWS_HOME/lib/jaxws-tools.jar" "$#"
Another reference:
If you are using the maven-jaxb2-plugin, prior to version 0.9.0, you can use the workaround described on this issue, in which this behaviour affected the plugin.
NetBeans update their tutorial for JDK8 and this Issue:
Getting Started with JAX-WS Web Services -> Enabling Access to External Schema
A very simple portable solution would be, to place the following line of code somewhere in a crucial part of your code, a part of which you are sure that it will be run (for example right in the main method):
System.setProperty("javax.xml.accessExternalDTD", "all");
This sets the needed system property programmatically, without having to do tricky maven pom.xml changes (which for some reason didn't work for me).
If you are using Intellij IDEA, in the maven tool window
select Maven Settings and expand the Maven drop down and select Runner.
Under the VM Options add -Djavax.xml.accessExternalSchema=all
Using RAD 9.6 with JDK 1.8 websphere 8.5 runtime on Windows,
editing the xjc.bat as in Generate Java gives "Failed to read external schema..." error didn't work with me, adding/updating the jaxb.properties didn't work as well,
however I edited the wsimport as in below note
you may modify the wsimport.bat file to specify the property directly as one of the jvm arguments like below:-Djavax.xml.accessExternalSchema=all
Our customers reported that the above solution worked for them.
as mentioned in SAXParseException, and it was the solution in my case.