यहां कंपोनेंट फैक्ट्री का उपयोग करने वाला एक उदाहरण है जो आपकी आवश्यकताओं को पूरा करना चाहिए (और आपके other question के साथ सहायता के लिए एक सरल एकीकरण परीक्षण शामिल है)। अस्वीकरण; कोड अच्छी तरह से लिखा नहीं है, बस उदाहरण के लिए।
कुछ सेवा इंटरफेस:
package net.earcam.example.servicecomponent;
public interface EchoService {
String REPEAT_PARAMETER = "repeat";
String FACTORY_DS = "echo.factory";
String NAME_DS = "echo";
String echo(String message);
}
और:
package net.earcam.example.servicecomponent;
public interface SequenceService {
long next();
}
फिर कार्यान्वयन:
import static net.earcam.example.servicecomponent.EchoService.FACTORY_DS;
import static net.earcam.example.servicecomponent.EchoService.NAME_DS;
import static org.apache.felix.scr.annotations.ReferenceCardinality.MANDATORY_UNARY;
import static org.apache.felix.scr.annotations.ReferencePolicy.DYNAMIC;
import net.earcam.example.servicecomponent.EchoService;
import net.earcam.example.servicecomponent.SequenceService;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.osgi.service.component.ComponentContext;
@Component(factory = FACTORY_DS, name = NAME_DS)
public class EchoServiceImp implements EchoService {
@Reference(cardinality = MANDATORY_UNARY, policy = DYNAMIC)
private SequenceService sequencer = null;
private transient int repeat = 1;
@Activate
protected void activate(final ComponentContext componentContext)
{
repeat = Integer.parseInt(componentContext.getProperties().get(REPEAT_PARAMETER).toString());
}
@Override
public String echo(final String message)
{
StringBuilder stringBuilder = new StringBuilder();
for(int i = 0; i < repeat; i++) {
addEchoElement(stringBuilder, message);
}
return stringBuilder.toString();
}
private void addEchoElement(final StringBuilder stringBuilder, final String message) {
stringBuilder.append(sequencer.next()).append(' ').append(message).append("\n");
}
protected void unbindSequencer()
{
sequencer = null;
}
protected void bindSequencer(final SequenceService sequencer)
{
this.sequencer = sequencer;
}
}
और:
package net.earcam.example.servicecomponent.internal;
import java.util.concurrent.atomic.AtomicLong;
import net.earcam.example.servicecomponent.SequenceService;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
/**
* @author caspar
*/
@Component
@Service
public class SequenceServiceImp implements SequenceService {
private AtomicLong sequence;
@Override
public long next()
{
return sequence.incrementAndGet();
}
@Activate
protected void activate()
{
sequence = new AtomicLong();
}
@Deactivate
protected void deactivate()
{
sequence = null;
}
}
एकीकरण परीक्षण जो पूरी चीज को चलाता है (नोट; एक मुख्य विधि है ताकि आप इसे चालू/बंद करने के दौरान इसे चलाएं)।
package net.earcam.example.servicecomponent.test;
import static org.ops4j.pax.exam.CoreOptions.*;
import static org.ops4j.pax.exam.OptionUtils.combine;
import static org.ops4j.pax.exam.spi.container.PaxExamRuntime.createContainer;
import static org.ops4j.pax.exam.spi.container.PaxExamRuntime.createTestSystem;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.earcam.example.servicecomponent.EchoService;
import net.earcam.example.servicecomponent.SequenceService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.Configuration;
import org.ops4j.pax.exam.junit.ExamReactorStrategy;
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
import org.ops4j.pax.exam.spi.reactors.EagerSingleStagedReactorFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentFactory;
import org.osgi.service.component.ComponentInstance;
@ExamReactorStrategy(EagerSingleStagedReactorFactory.class)
@RunWith(JUnit4TestRunner.class)
public class EchoServiceIntegrationTest {
public static void main(String[] args) {
try {
createContainer(
createTestSystem(
combine(
new EchoServiceIntegrationTest().config(),
profile("gogo"))
)).start();
} catch(Throwable t) {
t.printStackTrace();
}
}
@Configuration
public Option[] config()
{
return options(
felix(),
equinox(),
junitBundles(),
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("TRACE"),
mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.scr").versionAsInProject(),
bundle("file:" + findFileInCurrentDirectoryAndBelow(
Pattern.compile("net\\.earcam\\.example\\.servicecomponent\\-[\\.\\d]+(\\-SNAPSHOT)?\\.[wj]ar")))
);
}
@Test
public void bundleContextIsAvailable(BundleContext context)
{
Assert.assertNotNull("PAX Exam BundleContext available", context);
}
@Test
public void sequenceServiceIsAvailable(BundleContext context)
{
Assert.assertNotNull("SequenceService available", fetchService(context, SequenceService.class));
}
@Test
public void serviceResponseContainsThreeEchos(BundleContext context) throws Exception
{
final String message = "message";
final String expected = "1 " + message + "\n2 " + message + "\n3 " + message + "\n";
ComponentFactory factory = fetchComponentFactory(context, EchoService.FACTORY_DS);
Dictionary<String, String> properties = new Hashtable<String, String>();
properties.put(EchoService.REPEAT_PARAMETER, "3");
ComponentInstance instance = factory.newInstance(properties);
EchoService service = (EchoService) instance.getInstance();
String actual = service.echo(message);
Assert.assertEquals("Expected response", expected, actual);
}
private ComponentFactory fetchComponentFactory(BundleContext context, String componentFactoryId) throws Exception
{
String filter = "(component.factory=" + componentFactoryId + ")";
ServiceReference[] references = context.getServiceReferences(ComponentFactory.class.getCanonicalName(), filter);
return (references.length) == 0 ? null : (ComponentFactory) context.getService(references[0]);
}
private <T> T fetchService(BundleContext context, Class<T> clazz)
{
ServiceReference reference = context.getServiceReference(clazz.getCanonicalName());
@SuppressWarnings("unchecked")
T service = (T) context.getService(reference);
return service;
}
private String findFileInCurrentDirectoryAndBelow(final Pattern filePattern) {
FileFilter filter = new FileFilter() {
@Override
public boolean accept(File pathname) {
Matcher matcher = filePattern.matcher(pathname.getName());
return (matcher.matches());
}
};
return findFile(new File("."), filter, filePattern);
}
private String findFile(File directory, FileFilter filter, Pattern filePattern) {
File[] matches = directory.listFiles(filter);
if(matches != null && matches.length > 0) {
return matches[0].getAbsolutePath();
}
File[] subdirs = directory.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
for(final File subdir : subdirs) {
String found = findFile(subdir, filter, filePattern);
if(!"".equals(found)) {
return found;
}
}
throw new RuntimeException(new FileNotFoundException("No match for pattern: " + filePattern.pattern()));
}
}
और यहाँ Maven पोम है:
<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>net.earcam</groupId>
<artifactId>net.earcam.example.servicecomponent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<version.java.source>1.6</version.java.source>
<version.java.target>1.6</version.java.target>
<version.osgi>4.2.0</version.osgi>
<version.paxexam>2.1.0</version.paxexam>
<version.paxrunner>1.7.4</version.paxrunner>
<version.cometd>2.3.1</version.cometd>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>${version.osgi}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
<version>${version.osgi}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.4.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3.RC2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jmock</groupId>
<artifactId>jmock-junit4</artifactId>
<version>2.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId>
<version>${version.paxexam}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-paxrunner</artifactId>
<version>${version.paxexam}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-link-assembly</artifactId>
<version>${version.paxexam}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-testforge</artifactId>
<version>${version.paxexam}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.runner</groupId>
<artifactId>pax-runner-no-jcl</artifactId>
<version>${version.paxrunner}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr</artifactId>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${version.java.source}</source>
<target>${version.java.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<!-- Unit Tests -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.8.1</version>
<executions>
<execution>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<!-- Integration Tests -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>failsafe-maven-plugin</artifactId>
<version>2.4.3-alpha-1</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<phase>integration-test</phase>
</execution>
</executions>
<configuration>
<includes>
<include>**/*IntegrationTest.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>maven-paxexam-plugin</artifactId>
<version>1.2.3</version>
<executions>
<execution>
<id>generate-config</id>
<goals>
<goal>generate-depends-file</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!-- Process the DS annotations -->
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<id>generate-scr-descriptor</id>
<goals>
<goal>scr</goal>
</goals>
<phase>process-classes</phase>
<configuration>
<strictMode>true</strictMode>
<outputDirectory>${project.build.outputDirectory}/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<!-- Generate OSGi bundle MAINFEST.MF entries -->
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.4</version>
<extensions>true</extensions>
<configuration>
<supportedProjectTypes>
<supportedProjectType>jar</supportedProjectType>
</supportedProjectTypes>
<instructions>
<Bundle-Vendor>earcam</Bundle-Vendor>
<Service-Component>OSGI-INF/serviceComponents.xml</Service-Component>
<!-- PAX mangles this, it uses the name of the project for the symbolicname
of test bundle? <Bundle-SymbolicName>${project.name}</Bundle-SymbolicName> -->
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Bundle-Version>${project.version}</Bundle-Version>
<Export-Package>!${project.artifactId}.internal,${project.artifactId}.*</Export-Package>
<Import-Package>*</Import-Package>
</instructions>
</configuration>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
बातों का ध्यान रखना के एक जोड़े; मुझे परीक्षण के मॉड्यूल के अंदर मेरे एकीकरण परीक्षण पसंद हैं, इस तरह एमवीएन स्वच्छ स्थापित विफल रहता है अगर मेरा एकीकरण परीक्षण करता है - लेकिन सभी एकीकरण परीक्षणों के लिए एक एकल एकीकरण मॉड्यूल के साथ परियोजनाओं को देखना आम बात है। यह बदसूरत विधि findFileInCurrentDirectoryAndBelow(Pattern pattern)
बताता है जिसका उपयोग लक्ष्य निर्देशिका में वर्तमान मॉड्यूल के बंडल का पता लगाने के लिए किया जाता है, और यह मैवेन-बंडल-प्लगइन और मेवेन-स्क्र-प्लगइन प्लगइन के गैर-मानक सेटअप को भी समझाता है।
पैक्स-परीक्षा निर्भरता को उठाता है जिस तरह से आप निर्भरता और कॉन्फ़िगरेशन (जैसे बंडल आयात/निर्यात, डीएस परिवर्तन) में हर बदलाव के लिए मेवेन निर्माण को चलाने की आवश्यकता होती है। लेकिन एक बार ऐसा करने के बाद आप एक्लिप्स से परीक्षण चला सकते हैं/डीबग कर सकते हैं।
मैं एक टारबॉल में परियोजना डाल दिया here
HTH =)
आपकी सेवा वाले बंडल में ServiceB.class फ़ाइल नहीं होनी चाहिए। यदि ऐसा होता है, तो यह अलग-अलग बंडल के लिए अलग-अलग सेवा बी का उपयोग करेगा - यह गलत है। –
मुझे लगता है कि आप गलत समझा। यदि आप सर्विसफैक्टरी विशेषता निर्दिष्ट करते हैं तो डीएस प्रत्येक बंडल के लिए एक नया उदाहरण तैयार करेगा। आप उस घटक को प्राप्त कर सकते हैं जिसे आप घटक कॉन्टेक्स्ट से असाइन किया गया था। –