我目前正在尝试获取一个包含正在运行的服务工厂的简单包。
这是我的工厂类:
public class SvcFactory implements ServiceFactory<ServiceB> {
@Override
public ServiceB getService(Bundle bundle,
ServiceRegistration<ServiceB> registration) {
return new ServiceBImpl();
}
@Override
public void ungetService(Bundle bundle, ServiceRegistration<ServiceB> registration,
ServiceB service) {
}
}
这是我的服务,应该由工厂创建:
public class ServiceBImpl implements ServiceB {
private ServiceA svcA;
public void setA(ServiceA a) {
svcA = a;
}
}
最后是 OSGI-INF/component.xml
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="bundleb.internal.SvcFactory">
<implementation class="bundleb.internal.SvcFactory"/>
<reference bind="setA" cardinality="1..1" interface="bundlea.ServiceA" name="ServiceA" policy="static"/>
<service servicefactory="true">
<provide interface="bundleb.ServiceB"/>
</service>
</scr:component>
如果我在 equinox 中运行我的测试包(A、B 和 C),我会收到以下错误:
org.osgi.framework.ServiceException: org.eclipse.equinox.internal.ds.FactoryReg.getService() returned a service object that is not an instance of the service class bundleb.ServiceB
我在 Internet 上找不到有关使用组件定义中声明的 ServiceFeactories 的很多信息。即使是“OSGi 和 Equinox”这本书也没有告诉我太多关于使用它们的信息。 任何人都可以向我解释我做错了什么吗?
最佳答案
这是一个使用 ComponentFactory 的示例,它应该符合您的需要(并包含一个简单的集成测试来帮助您 other question )。免责声明;代码写得不好,只是为了举例。
一些服务接口(interface):
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;
}
}
驱动整个事情的集成测试(注意;有一个主要方法,因此您可以在启动/停止 bundle 等时运行它)。
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 pom:
<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>
有几点需要注意;我喜欢我在他们测试的模块中进行集成测试,如果我的集成测试失败,那么 mvn clean install deploy 就会失败 - 但通常会看到项目具有用于所有集成测试的单个集成模块。这解释了丑陋的方法 findFileInCurrentDirectoryAndBelow(Pattern pattern) 用于在目标目录中定位当前模块的包,还解释了 maven-bundle-plugin 和 maven-scr 的非标准设置-插件插件。
此外,Pax-Exam 选择依赖项的方式要求您为依赖项和配置中的每个更改运行 Maven 构建(例如,捆绑导入/导出、DS 更改)。但是一旦完成,您就可以从 Eclipse 运行/调试测试。
我已经把这个项目放在压缩包里了 here
HTH =)
关于java - osgi:使用服务工厂?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7033222/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h