how to use solr with a c++ application - java

i' m developping an application in c++ and i wanna using solr to index sqlite database, i searched in net and i finded that i need to use JNI :
http://randr.svbtle.com/experiment-with-embedded-solr-in-java-and-c
But i finded many problems with JARS(i used the jars under \solr-4.9.0\dist\solrj-lib and \solr-4.9.0\dist and \solr-4.9.0\example\lib\ext )
i learned that i can use JCC also,my question is what's the best solution,and if it was with JNI can you details to me how to configure solr to be called from a c++ application and what jars i need exactly

I have never used Solr before, but here's one way to go about this with JavaCPP and Maven. First, create this pom.xml build file:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>solrtest</artifactId>
<version>0</version>
<dependencies>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>0.9</version>
</dependency>
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-core</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<configuration>
<header>true</header>
<includePath>.</includePath>
<linkPath>.</linkPath>
<preloadPath>.</preloadPath>
</configuration>
<executions>
<execution>
<id>process-classes</id>
<phase>process-classes</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<artifactId>solr-core</artifactId>
<groupId>org.apache.solr</groupId>
<version>1.4.1</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
As well as this src/main/java/SolrTest.java source file:
import java.io.*;
import org.apache.solr.core.*;
import org.apache.solr.client.solrj.*;
import org.apache.solr.client.solrj.embedded.*;
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
public class SolrTest {
static SolrServer createServer(String coreName) throws Exception {
CoreContainer coreContainer = new CoreContainer();
CoreDescriptor discriptor = new CoreDescriptor(coreContainer, coreName, new File("/some/path/", coreName).getAbsolutePath());
SolrCore solrCore = coreContainer.create(discriptor);
coreContainer.register(solrCore, false);
return new EmbeddedSolrServer(coreContainer, coreName);
}
static class Query extends FunctionPointer {
public #Name("query") String call(String string) throws Exception {
createServer(string);
return string;
}
}
}
Then we can execute mvn package, and after it has downloaded a whole bunch of things and built stuff for us, we're going to end up with target/solrtest-0.jar as well as a header file and a native library file in the target/classes subdirectory. Now, we can link all this together in C++ with a program like this:
#include <iostream>
#include "target/classes/jniSolrTest.h"
int main() {
const char *argv[] = { "-Djava.class.path=target/solrtest-0.jar" };
JavaCPP_init(1, argv);
try {
query("test");
} catch (std::exception &e) {
std::cout << e.what() << std::endl;
}
JavaCPP_uninit();
}
That we can compile and run this way under Linux x86_64, for example, but we can do the equivalent on other platforms:
$ g++ -I/usr/lib/jvm/java/include/ -I/usr/lib/jvm/java/include/linux/ target/classes/linux-x86_64/libjniSolrTest.so query.cpp -o query
$ ./query
And we get a proper exception from Solr:
[main] INFO org.apache.solr.core.SolrResourceLoader - JNDI not configured for solr (NoInitialContextEx)
[main] INFO org.apache.solr.core.SolrResourceLoader - solr home defaulted to 'solr/' (could not find system property or JNDI)
[main] INFO org.apache.solr.core.SolrResourceLoader - Solr home set to '/some/path/test/'
java.lang.RuntimeException: Can't find resource 'solrconfig.xml' in classpath or '/some/path/test/conf/', cwd=/home/saudet/solrtest
Something that we can fix by installing stuff for Solr...

Related

TeaVM and WebAssembly - build errors

I want to use Java code in the web. For this I want to convert Java to WASM and use this wasm-file in JavaScript. For converting Java to WebAssembly, I am using TeaVM.
First, I created an archetype with this command: mvn archetype:generate -DarchetypeGroupId=org.teavm.flavour -DarchetypeArtifactId=teavm-flavour-application -DarchetypeVersion=0.2.0
In addition, I added these two dependencies (according to http://blog.dmitryalexandrov.net/webassembly-for-java-developers/):
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-jso-apis</artifactId>
<version>${teavm.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-interop</artifactId>
<version>${teavm.version}</version>
</dependency>
and added the following in the plugin section:
<targetType>WEBASSEMBLY</targetType>
<optimizationLevel>FULL</optimizationLevel>
<heapSize>8</heapSize>
My Java file:
#BindTemplate("templates/client.html")
public class Client extends ApplicationTemplate {
private String userName = "ABC";
public static void main(String[] args) {
Client client = new Client();
client.bind("application-content");
}
#Export(name = "getUserName")
public String getUserName() {
return userName;
}
}
But when I am doing mvn clean package, I am getting to following error (but a wasm file is created):
my complete pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>my.company</groupId>
<artifactId>java_wasm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<flavour.version>0.2.0</flavour.version>
<teavm.version>0.6.0</teavm.version>
<jackson.version>2.5.4</jackson.version>
</properties>
<dependencies>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-classlib</artifactId>
<version>${teavm.version}</version>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-metaprogramming-impl</artifactId>
<version>${teavm.version}</version>
</dependency>
<dependency>
<groupId>org.teavm.flavour</groupId>
<artifactId>teavm-flavour-widgets</artifactId>
<version>${flavour.version}</version>
</dependency>
<dependency>
<groupId>org.teavm.flavour</groupId>
<artifactId>teavm-flavour-rest</artifactId>
<version>${flavour.version}</version>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-jso-apis</artifactId>
<version>${teavm.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-interop</artifactId>
<version>${teavm.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<webResources>
<resource>
<directory>${project.build.directory}/generated/js</directory>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>org.teavm</groupId>
<artifactId>teavm-maven-plugin</artifactId>
<version>${teavm.version}</version>
<executions>
<execution>
<id>web-client</id>
<phase>prepare-package</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>
<mainClass>my.company.Client</mainClass>
<minifying>true</minifying>
<debugInformationGenerated>true</debugInformationGenerated>
<sourceMapsGenerated>true</sourceMapsGenerated>
<sourceFilesCopied>true</sourceFilesCopied>
<optimizationLevel>ADVANCED</optimizationLevel>
<targetType>WEBASSEMBLY</targetType>
<optimizationLevel>FULL</optimizationLevel>
<heapSize>8</heapSize>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
How can I create a complete WASM without errors? Thank you in advance!
Wasm backend of TeaVM does not support JSO interop layer. It also supports subset of features available in JavaScript backend. So there's no way to make TeaVM Flavour work in Wasm, instead your should prefer JavaScript target. If you want to learn how to deal with Wasm BE, you can take a look at example.
Wasm has proven to be extremely inappropriate to run Java, so I recommend to use JavaScript BE of TeaVM. Also, please note that official site (htts://teavm.org) lists links where you can get help (google groups, gitter, direct email). I don't follow StackOverflow questions about TeaVM and don't receive notifications from SO.

execute maven project with Json from command line

I am starting a project to read and analyze a JSON-file with JAVA 8. To have it run in Eclipse, I turned it into a maven project and added this dependency :
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1</version>
<scope>runtime</scope>
</dependency>
Within Eclipse , there is no problem, but when I run it from command line, I get this error:
Provider org.glassfish.json.JsonProviderImpl not found
In futur I want to run it on a server without an Eclipse installation.
How can I get it running ?
Please see this question. It will help you create a jar file that has all the dependencies built into it. I would not suggest rewriting things and to use libraries freely. You code much faster and in more bug free ways when you do not code it yourself.
Once you have done this you will be able to run java -jar on the jar file and your application will run. If you would like to just have the thing run you can download the jar and add it to the classpath variable that you pass the java command line.
thanks a lot. Following maven configuration gets it work for command line :
<plugins>
..
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>data.Parser</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1</version>
<scope>runtime</scope>
</dependency>
</dependencies>
if you want simply deserialize using Gson. you use this sample program
import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import com.google.gson.Gson;
public class Main {
public static void main(String[] args) throws IOException {
String json = FileUtils.readFileToString(new File("PATH_TO_JSON"), "UTF-8");
Gson deserializer = new Gson();
System.out.println(deserializer.fromJson(json, Map.class));
}
}
you will need following dependencies
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>

How to run jar file of a maven project generated after build?

I made a simple project with a few tests in it and I want to be able to launch tests on other computers. I built the project using Run As -> Maven build... -> Goals: package in Eclipse, and I found a jar file in target folder of the project. But when I try to run it in cmd using java -jar project.jar I get the following error:
Error: Main method not found in class com.example.TestPurchase, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
As far as I know, TestNG doesn't need any Main method, because of the annotations.
That brings me to some questions:
Is something wrong with how I build my project?
Did I understand the method of executing tests via jar file correct?
Do I even have to use that jar file? Because I can run tests from command line being in project folder using mvn test
Here is my pom.xml file:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>Sightsy</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<selenium.version>3.12.0</selenium.version>
<testng.version>6.13.1</testng.version>
<javafaker.version>0.14</javafaker.version>
<guava.version>23.2-jre</guava.version>
<extentreports.version>3.0.7</extentreports.version>
<extenttestng.version>1.3.1</extenttestng.version>
<assertj.version>3.8.0</assertj.version>
<maven.compiler.version>3.7.0</maven.compiler.version>
<commons.version>3.7</commons.version>
<commons.io.version>2.6</commons.io.version>
</properties>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
</dependency>
<dependency>
<groupId>com.github.javafaker</groupId>
<artifactId>javafaker</artifactId>
<version>${javafaker.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>${extentreports.version}</version>
</dependency>
<dependency>
<groupId>com.vimalselvam</groupId>
<artifactId>testng-extentsreport</artifactId>
<version>${extenttestng.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.TestPurchase</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.21.0</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/main/resources/suites/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
I'm not familiar with TestNG framework, but my understanding is as following:
When "mvn package" is executed, your project is "validated", "compiled" and then "packed". During compilation, your code is changed to bytecode and can be interpreted (executed) by java virtual machine (JVM). This compiled code has only your application (I assume, that this is an application that is executed on Java server).
During the "package" step, these compiled classes (without tests) are put together in jar file. This jar file should contain only your application (again, without tests) - this is what you want because your jar file is smaller and contain only what is really needed.
Now when "mvn test" is executed, classes with test code are compiled and then executed. TestNG add the main function "automatically" so JVM knows what to do. Please note that running again "mvn package" will still NOT include these tests in jar file.
To address your questions directly:
Ad 1. No
Ad 2. Yes, "mvn test" is the correct way.
Ad 3. No, you should not use jar file during testing. It is used later during deployment.
First of all, you must have a separate class with "main" method, where you will specify your xml suite files.
package com.example;
import java.util.ArrayList;
import java.util.List;
import org.testng.TestNG;
public class MainClass {
public static void main(String[] args) {
TestNG testSuite = new TestNG();
List<String> suites = new ArrayList<String>();
suites.add("path_to_your_xml_suite_file_in_target_folder");
testSuite.setTestSuites(suites);
testSuite.run();
}
}
Then, you will need to specify this class with "main" method in configuration of maven-shade-plugin in pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.TestNGMainClass</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
Then, when you will execute mvn build package without performing tests, you will have a fully working executable jar file in target folder, which you can launch in command line using java -jar name_of_you_jar_file.jar. It will need drivers and xml suite files to work

Aspectj getting compile error when using the Java 8 class Supplier

I'm trying to use some nifty lazy logging tricks in my logging layer but AspectJ is choking on it. I have a facade in front of log4j. Here's the code:
public void debug ( Supplier<String> message )
{
if( isDebugEnabled() )
{
debug( message.get() );
}
}
The error:
[ERROR] The type java.util.function.Supplier cannot be resolved. It is indirectly referenced from required .class files
/home/Build/src/Core/Database/src/com/BasicDao.java:1006
LOGGER.debug( "Retry number: "+retryCount+"DB Lock Conflict, sleeping "+retrySleepTime );
Here's my pom bits:
<plugin>
<!-- This plugin integrates aspectj into our build cycle -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.5</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
And:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.5</version>
</dependency>
Other interesting facts are that this compiles fine within Eclipse, but I get this error when running mvn package from a Linux command line.
Upon further trial/error we have discovered that if we manually set JAVA_HOME to point to Java 8 then it compiles. It looks like AspectJ requires your JAVA_HOME to point to the right version of Java. In the main pom we are directing maven to use the specific version of Java with:
<executable>${JAVA_1_8_HOME}/bin/javac</executable>
<jvm>${JAVA_1_8_HOME}/jre/bin/java</jvm>
Neither of those seemed to work with the aspectj-maven-plugin configuration.

Problems testing services created with maven-scr-plugin when using pax-exam

I've set up a very simple "HelloWorld" service to demonstrate my problem. It uses the maven-scr-plugin to generate a service descriptor and has a pax-exam unit test. But when I try to run 'mvn clean test' it blocks for a while before giving me this error:
org.ops4j.pax.swissbox.tracker.ServiceLookupException: gave up waiting for service com.liveops.examples.osgi.helloworld.HelloWorldService
If I run 'mvn -DskipTests=true package' and then run 'mvn test' (without clean)
it works. The difference seems to be the addition of this line in my META-INF/M
ANIFEST.MF file:
Service-Component: OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml
Does anyone know if there is a way to make sure this line is added earlier in the build process so that 'mvn clean test' will pass? Or is there something else I might be doing wrong?
For reference, here is the pom.xml, the service, and the unit test.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.liveops.examples</groupId>
<artifactId>HelloWorldService</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-native</artifactId>
<version>3.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.url</groupId>
<artifactId>pax-url-aether</artifactId>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-link-mvn</artifactId>
<version>3.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.framework</artifactId>
<version>4.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.9.0</version>
</dependency>
</dependencies>
<properties>
<namespace>com.liveops.examples.osgi.helloworld</namespace>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<!--
| the following instructions build a simple set of public/private classes into an OSGi bundle
-->
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.name}</Bundle-SymbolicName>
<Bundle-Version>${project.version}</Bundle-Version>
<!-- Bundle-Activator>${namespace}.internal.HelloActivator</Bundle-Activator -->
<!--
| assume public classes are in the top package, and private classes are under ".internal"
-->
<Export-Package>!${namespace}.internal.*,${namespace}.*;version="${project.version}"</Export-Package>
<Private-Package>${namespace}.internal.*</Private-Package>
<!--
| each module can override these defaults in their osgi.bnd file
-->
<!--_include>-osgi.bnd</_include-->
</instructions>
</configuration>
<executions>
<execution>
<id>generate-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<version>1.9.0</version>
<configuration>
<supportedProjectTypes>
<supportedProjectType>jar</supportedProjectType>
<supportedProjectType>bundle</supportedProjectType>
<supportedProjectType>war</supportedProjectType>
</supportedProjectTypes>
<generateAccessors>true</generateAccessors>
<strictMode>true</strictMode>
<specVersion>1.1</specVersion>
<outputDirectory>target/classes</outputDirectory>
</configuration>
<executions>
<execution>
<id>generate-scr-scrdescriptor</id>
<goals>
<goal>scr</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
HelloWorld Implementation class
package com.liveops.examples.osgi.helloworld.internal;
import com.liveops.examples.osgi.helloworld.HelloWorldService;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Component;
#Component
#Service(HelloWorldService.class)
public class HelloImpl implements HelloWorldService
{
public String helloWorld(String personalization)
{
return "Hello " + personalization + "!";
}
}
The unit test
package com.liveops.examples.osgi.helloworld.internal;
import com.liveops.examples.osgi.helloworld.HelloWorldService;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.util.PathUtils;
import javax.inject.Inject;
import static org.ops4j.pax.exam.CoreOptions.*;
#RunWith(PaxExam.class)
public class HelloImplTest
{
#Inject
HelloWorldService hws;
#Configuration
public static Option[] configuration() throws Exception{
return options(
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN"),
mavenBundle("org.apache.felix", "org.apache.felix.scr", "1.6.2"),
bundle("reference:file:" + PathUtils.getBaseDir() + "/target/classes"),
junitBundles());
}
#Test
public void testInjection()
{
Assert.assertNotNull(hws);
}
#Test
public void testHelloWorld() throws Exception
{
Assert.assertNotNull(hws);
Assert.assertEquals("Hello UnitTest!", hws.helloWorld("UnitTest"));
}
}
Use the ProbeBuilder to enhance your tested bundle:
#ProbeBuilder
public TestProbeBuilder probeConfiguration(TestProbeBuilder probe) {
probe.setHeader("Service-Component", "OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml");
return probe;
}
This most likely is all that's missing.
EDIT:
just in case you're trying to use pax-exam in the same bundle you need to take certain actions in your configuration method:
streamBundle(bundle()
.add(SomceClass.class).add("OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml", new File("src/main/resources/OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml")
.toURL())
.set("Service-Component", "OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml")
.build()).start()
a complete sample can be found at here
I may have a fix for this, though it seems a bit in-elegant. I can explicitly add the Service-Component to the maven-bundle-plugin section of the pom file.
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.name}</Bundle-SymbolicName>
<Bundle-Version>${project.version}</Bundle-Version>
<Export-Package>!${namespace}.internal.*,${namespace}.*;version="${project.version}"</Export-Package>
<Private-Package>${namespace}.internal.*</Private-Package>
<!--Explicitly add the components no that they can be found in the test phase -->
<Service-Component>OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml</Service-Component>
</instructions>
</configuration>
<executions>
<execution>
<id>generate-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
</plugin>
Please let me know if anyone can think of a better way.
The Maven SCR Plugin only generates the service component descriptors but it does not include them in the manifest automatically.
So there's nothing inelegant about including a <Service-Component> instruction in the Maven Bundle Plugin configuration, that's just the documented usage.
Since the manifest header is missing, SCR does not register any services on behalf of your bundle, and that's why Pax Exam can't find the required service.

Categories