http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportService.java ---------------------------------------------------------------------- diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportService.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportService.java deleted file mode 100644 index fa4a63e..0000000 --- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportService.java +++ /dev/null @@ -1,137 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cxf.dosgi.systests2.multi; - -import java.io.IOException; -import java.net.URL; -import java.util.Map; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; -import org.apache.cxf.dosgi.samples.greeter.GreeterData; -import org.apache.cxf.dosgi.samples.greeter.GreeterException; -import org.apache.cxf.dosgi.samples.greeter.GreeterService; -import org.apache.cxf.dosgi.samples.greeter.GreetingPhrase; -import org.apache.cxf.frontend.ClientProxyFactoryBean; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.ops4j.pax.exam.Configuration; -import org.ops4j.pax.exam.Option; -import org.ops4j.pax.exam.junit.PaxExam; - -import static org.ops4j.pax.exam.CoreOptions.frameworkStartLevel; -import static org.ops4j.pax.exam.CoreOptions.mavenBundle; -import static org.ops4j.pax.exam.CoreOptions.systemProperty; - -@RunWith(PaxExam.class) -public class TestExportService extends AbstractDosgiTest { - - @Configuration - public static Option[] configure() throws Exception { - return new Option[] { - MultiBundleTools.getDistroWithDiscovery(), - systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"), - mavenBundle().groupId("org.apache.servicemix.bundles") - .artifactId("org.apache.servicemix.bundles.junit").version("4.9_2"), - mavenBundle().groupId("org.apache.cxf.dosgi.samples") - .artifactId("cxf-dosgi-ri-samples-greeter-interface").versionAsInProject(), - mavenBundle().groupId("org.apache.cxf.dosgi.samples") - .artifactId("cxf-dosgi-ri-samples-greeter-impl").versionAsInProject(), - mavenBundle().groupId("org.apache.cxf.dosgi.systests") - .artifactId("cxf-dosgi-ri-systests2-common").versionAsInProject(), frameworkStartLevel(100), - //CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005") - }; - } - - @Test - public void testAccessEndpoint() throws Exception { - assertBundlesStarted(); - waitPort(9090); - - checkWsdl(new URL("http://localhost:9090/greeter?wsdl")); - - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(ClientProxyFactoryBean.class.getClassLoader()); - try { - checkServiceCall("http://localhost:9090/greeter"); - } finally { - Thread.currentThread().setContextClassLoader(cl); - } - } - - private void checkServiceCall(String serviceUri) { - GreeterService client = createGreeterServiceProxy(serviceUri); - - Map<GreetingPhrase, String> greetings = client.greetMe("Fred"); - Assert.assertEquals("Fred", greetings.get(new GreetingPhrase("Hello"))); - System.out.println("Invocation result: " + greetings); - - try { - GreeterData gd = new GreeterDataImpl("Stranger", 11, true); - client.greetMe(gd); - Assert.fail("GreeterException has to be thrown"); - } catch (GreeterException ex) { - Assert.assertEquals("Wrong exception message", "GreeterService can not greet Stranger", - ex.toString()); - } - } - - private void checkWsdl(URL wsdlURL) throws ParserConfigurationException, SAXException, IOException { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setValidating(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.parse(wsdlURL.openStream()); - Element el = doc.getDocumentElement(); - Assert.assertEquals("definitions", el.getLocalName()); - Assert.assertEquals("http://schemas.xmlsoap.org/wsdl/", el.getNamespaceURI()); - Assert.assertEquals("GreeterService", el.getAttribute("name")); - } - - class GreeterDataImpl implements GreeterData { - - private String name; - private int age; - private boolean exception; - - GreeterDataImpl(String n, int a, boolean ex) { - name = n; - age = a; - exception = ex; - } - - public String getName() { - return name; - } - - public int getAge() { - return age; - } - - public boolean isException() { - return exception; - } - } -}
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestImportService.java ---------------------------------------------------------------------- diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestImportService.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestImportService.java deleted file mode 100644 index efc334b..0000000 --- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestImportService.java +++ /dev/null @@ -1,161 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cxf.dosgi.systests2.multi; - -import java.io.InputStream; -import java.util.Dictionary; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Map; - -import javax.inject.Inject; - -import org.apache.cxf.aegis.databinding.AegisDatabinding; -import org.apache.cxf.dosgi.samples.greeter.GreeterData; -import org.apache.cxf.dosgi.samples.greeter.GreeterException; -import org.apache.cxf.dosgi.samples.greeter.GreeterService; -import org.apache.cxf.dosgi.samples.greeter.GreetingPhrase; -import org.apache.cxf.dosgi.systests2.common.test1.GreeterDataImpl; -import org.apache.cxf.dosgi.systests2.common.test1.MyActivator; -import org.apache.cxf.dosgi.systests2.common.test1.MyServiceTracker; -import org.apache.cxf.dosgi.systests2.common.test1.StartServiceTracker; -import org.apache.cxf.endpoint.Server; -import org.apache.cxf.frontend.ServerFactoryBean; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.ops4j.pax.exam.Configuration; -import org.ops4j.pax.exam.Option; -import org.ops4j.pax.exam.junit.PaxExam; -import org.ops4j.pax.tinybundles.core.TinyBundles; -import org.osgi.framework.BundleContext; -import org.osgi.framework.Constants; -import org.osgi.framework.ServiceReference; - -import static org.ops4j.pax.exam.CoreOptions.frameworkStartLevel; -import static org.ops4j.pax.exam.CoreOptions.mavenBundle; -import static org.ops4j.pax.exam.CoreOptions.provision; -import static org.ops4j.pax.exam.CoreOptions.systemProperty; - -@RunWith(PaxExam.class) -public class TestImportService extends AbstractDosgiTest { - - @Inject - BundleContext bundleContext; - - @Configuration - public static Option[] configure() throws Exception { - return new Option[] { - MultiBundleTools.getDistroWithDiscovery(), - systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"), - mavenBundle().groupId("org.apache.cxf.dosgi.samples") - .artifactId("cxf-dosgi-ri-samples-greeter-interface").versionAsInProject(), - mavenBundle().groupId("org.apache.servicemix.bundles") - .artifactId("org.apache.servicemix.bundles.junit").version("4.9_2"), - mavenBundle().groupId("org.apache.cxf.dosgi.systests") - .artifactId("cxf-dosgi-ri-systests2-common").versionAsInProject(), - provision(createServiceConsumerBundle()), - // increase for debugging - systemProperty("org.apache.cxf.dosgi.test.serviceWaitTimeout").value( - System.getProperty("org.apache.cxf.dosgi.test.serviceWaitTimeout", "200")), - frameworkStartLevel(100), - //CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005") - }; - } - - protected static InputStream createServiceConsumerBundle() { - return TinyBundles.bundle() - .add(MyActivator.class) - .add(MyServiceTracker.class) - .add(StartServiceTracker.class) - .add(GreeterDataImpl.class) - .add("OSGI-INF/remote-service/remote-services.xml", TestImportService.class.getResource("/rs-test1.xml")) - .set(Constants.BUNDLE_SYMBOLICNAME, "testClientBundle") - .set(Constants.EXPORT_PACKAGE, "org.apache.cxf.dosgi.systests2.common.test1") - .set(Constants.BUNDLE_ACTIVATOR, MyActivator.class.getName()) - .build(TinyBundles.withBnd()); - } - - @Test - public void testClientConsumer() throws Exception { - // This test tests the consumer side of Distributed OSGi. It works as follows: - // 1. It creates a little test bundle on the fly and starts that in the framework - // (this happens in the configure() method above). The test bundle waits until its - // instructed to start doing stuff. It's give this instruction via a service that is - // registered by this test (the service is of type java.lang.Object and has testName=test1). - // 2. The test manually creates a CXF server of the appropriate type (using ServerFactoryBean) - // 3. It signals the client bundle by registering a service to start doing its work. - // This registers a ServiceTracker in the client bundle for the remote service that is created - // by the test in step 2. The client bundle knows about the address through the - // remote-services.xml file. - // 4. The client bundle will invoke the remote service and record the results in a service that it - // registers in the Service Registry. - // 5. The test waits for this service to appear and then checks the results which are available as - // a service property. - - // Set up a Server in the test - Server server = null; - try { - server = publishTestGreeter(); - - Dictionary<String, Object> props = new Hashtable<String, Object>(); - props.put("testName", "test1"); - bundleContext.registerService(Object.class.getName(), new Object(), props); - - // Wait for the service tracker in the test bundle to register a service with the test result - @SuppressWarnings("rawtypes") - ServiceReference ref = waitService(bundleContext, String.class, "(testResult=test1)", 20); - Assert.assertEquals("HiOSGi;exception", ref.getProperty("result")); - } finally { - if (server != null) { - server.stop(); - } - - } - } - - private Server publishTestGreeter() { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - try { - Thread.currentThread().setContextClassLoader(ServerFactoryBean.class.getClassLoader()); - ServerFactoryBean factory = new ServerFactoryBean(); - factory.setServiceClass(GreeterService.class); - factory.setAddress("http://localhost:9191/grrr"); - factory.getServiceFactory().setDataBinding(new AegisDatabinding()); - factory.setServiceBean(new TestGreeter()); - return factory.create(); - } finally { - Thread.currentThread().setContextClassLoader(cl); - } - } - - public static class TestGreeter implements GreeterService { - - public Map<GreetingPhrase, String> greetMe(String name) { - Map<GreetingPhrase, String> m = new HashMap<GreetingPhrase, String>(); - GreetingPhrase gp = new GreetingPhrase("Hi"); - m.put(gp, name); - return m; - } - - public GreetingPhrase[] greetMe(GreeterData gd) throws GreeterException { - throw new GreeterException("TestGreeter"); - } - } -} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/AddGreetingPhraseInterceptor.java ---------------------------------------------------------------------- diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/AddGreetingPhraseInterceptor.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/AddGreetingPhraseInterceptor.java deleted file mode 100644 index a3a19be..0000000 --- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/AddGreetingPhraseInterceptor.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cxf.dosgi.systests2.multi.customintent; - -import java.util.List; -import java.util.Map; - -import org.apache.cxf.dosgi.samples.greeter.GreetingPhrase; -import org.apache.cxf.helpers.CastUtils; -import org.apache.cxf.interceptor.Fault; -import org.apache.cxf.message.Message; -import org.apache.cxf.message.MessageContentsList; -import org.apache.cxf.phase.AbstractPhaseInterceptor; - -public final class AddGreetingPhraseInterceptor extends AbstractPhaseInterceptor<Message> { - - AddGreetingPhraseInterceptor(String phase) { - super(phase); - } - - public void handleMessage(Message message) throws Fault { - MessageContentsList contents = (MessageContentsList) message.getContent(List.class); - Map<GreetingPhrase, String> result = CastUtils.cast((Map<?, ?>)contents.get(0)); - result.put(new GreetingPhrase("Hi from custom intent"), "customintent"); - //Object content1 = contents.iterator().next(); - System.out.println(message); - } -} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomFeature.java ---------------------------------------------------------------------- diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomFeature.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomFeature.java deleted file mode 100644 index abac14f..0000000 --- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomFeature.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cxf.dosgi.systests2.multi.customintent; - -import org.apache.cxf.Bus; -import org.apache.cxf.feature.AbstractFeature; -import org.apache.cxf.interceptor.InterceptorProvider; -import org.apache.cxf.phase.Phase; - -public final class CustomFeature extends AbstractFeature { - - @Override - protected void initializeProvider(InterceptorProvider provider, Bus bus) { - provider.getOutInterceptors().add(0, new AddGreetingPhraseInterceptor(Phase.USER_LOGICAL)); - super.initializeProvider(provider, bus); - } -} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomIntentActivator.java ---------------------------------------------------------------------- diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomIntentActivator.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomIntentActivator.java deleted file mode 100644 index ca4efda..0000000 --- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomIntentActivator.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cxf.dosgi.systests2.multi.customintent; - -import java.util.Dictionary; -import java.util.Hashtable; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - -public class CustomIntentActivator implements BundleActivator { - - public void start(BundleContext context) throws Exception { - Dictionary<String, String> props = new Hashtable<String, String>(); - props.put("org.apache.cxf.dosgi.IntentName", "myIntent"); - context.registerService(Object.class.getName(), new CustomFeature(), props); - } - - public void stop(BundleContext context) throws Exception { - } -} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/EmptyGreeterService.java ---------------------------------------------------------------------- diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/EmptyGreeterService.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/EmptyGreeterService.java deleted file mode 100644 index 2c0108d..0000000 --- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/EmptyGreeterService.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cxf.dosgi.systests2.multi.customintent.service; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.cxf.dosgi.samples.greeter.GreeterData; -import org.apache.cxf.dosgi.samples.greeter.GreeterException; -import org.apache.cxf.dosgi.samples.greeter.GreeterService; -import org.apache.cxf.dosgi.samples.greeter.GreetingPhrase; - -public final class EmptyGreeterService implements GreeterService { - - /** - * Return an empty array. Our custom intent should add a GreetingPhrase - */ - public GreetingPhrase[] greetMe(GreeterData name) throws GreeterException { - return new GreetingPhrase[]{}; - } - - public Map<GreetingPhrase, String> greetMe(String name) { - return new HashMap<GreetingPhrase, String>(); - } -} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/GreeterServiceWithCustomIntentActivator.java ---------------------------------------------------------------------- diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/GreeterServiceWithCustomIntentActivator.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/GreeterServiceWithCustomIntentActivator.java deleted file mode 100644 index bcf6016..0000000 --- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/GreeterServiceWithCustomIntentActivator.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cxf.dosgi.systests2.multi.customintent.service; - -import java.util.Dictionary; -import java.util.Hashtable; - -import org.apache.cxf.dosgi.samples.greeter.GreeterService; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.service.remoteserviceadmin.RemoteConstants; - -public class GreeterServiceWithCustomIntentActivator implements BundleActivator { - - public void start(BundleContext context) throws Exception { - Dictionary<String, String> props = new Hashtable<String, String>(); - props.put(RemoteConstants.SERVICE_EXPORTED_INTERFACES, "*"); - props.put(RemoteConstants.SERVICE_EXPORTED_CONFIGS, "org.apache.cxf.ws"); - props.put("org.apache.cxf.ws.address", "http://localhost:9090/greeter"); - props.put(RemoteConstants.SERVICE_EXPORTED_INTENTS, "myIntent"); - context.registerService(GreeterService.class.getName(), new EmptyGreeterService(), props); - } - - public void stop(BundleContext context) throws Exception { - } -} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslate.java ---------------------------------------------------------------------- diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslate.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslate.java deleted file mode 100644 index 3a55c0e..0000000 --- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslate.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cxf.dosgi.systests2.multi.rest; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; - -public interface RestTranslate { - - @GET - String englishWords(); - - @GET - @Path("/{word}") - String getTranslation(@PathParam("word") String word); - -} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslateImpl.java ---------------------------------------------------------------------- diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslateImpl.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslateImpl.java deleted file mode 100644 index 640b0c9..0000000 --- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslateImpl.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cxf.dosgi.systests2.multi.rest; - -import java.util.HashMap; -import java.util.Map; - -public class RestTranslateImpl implements RestTranslate { - Map<String, String> translation; - - public RestTranslateImpl() { - translation = new HashMap<String, String>(); - translation.put("hello", "hallo"); - } - - @Override - public String englishWords() { - return translation.keySet().toString(); - } - - @Override - public String getTranslation(String word) { - return translation.get(word); - } -} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/TranslateActivator.java ---------------------------------------------------------------------- diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/TranslateActivator.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/TranslateActivator.java deleted file mode 100644 index 1c48fb5..0000000 --- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/TranslateActivator.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cxf.dosgi.systests2.multi.rest; - -import java.util.Dictionary; -import java.util.Hashtable; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - -public class TranslateActivator implements BundleActivator { - - public void start(BundleContext context) throws Exception { - Dictionary<String, String> props = new Hashtable<String, String>(); - props.put("service.exported.interfaces", "*"); - props.put("service.exported.configs", "org.apache.cxf.rs"); - props.put("service.exported.intents", "HTTP"); - props.put("org.apache.cxf.rs.address", "/translate"); - context.registerService(RestTranslate.class.getName(), new RestTranslateImpl(), props); - } - - public void stop(BundleContext context) throws Exception { - } -} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/systests2/multi-bundle/src/test/resources/log4j.properties b/systests2/multi-bundle/src/test/resources/log4j.properties deleted file mode 100644 index 2f206d5..0000000 --- a/systests2/multi-bundle/src/test/resources/log4j.properties +++ /dev/null @@ -1,13 +0,0 @@ -# Set root logger level to DEBUG and its only appender to A1. -log4j.rootLogger=INFO, A1 - -# A1 is set to be a ConsoleAppender. -log4j.appender.A1=org.apache.log4j.ConsoleAppender - -# A1 uses PatternLayout. -log4j.appender.A1.layout=org.apache.log4j.PatternLayout -log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n - -log4j.logger.org.ops4j.pax.scanner=WARN -log4j.logger.org.ops4j.pax.runner=WARN -log4j.logger.org.ops4j.pax.url=WARN http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/pom.xml ---------------------------------------------------------------------- diff --git a/systests2/pom.xml b/systests2/pom.xml deleted file mode 100644 index 93d70e2..0000000 --- a/systests2/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version='1.0' encoding='UTF-8' ?> -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. ---> -<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/maven-v4_0_0.xsd"> - - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.apache.cxf.dosgi</groupId> - <artifactId>cxf-dosgi-ri-parent</artifactId> - <version>1.8-SNAPSHOT</version> - <relativePath>../parent/pom.xml</relativePath> - </parent> - - <groupId>org.apache.cxf.dosgi.systests</groupId> - <artifactId>cxf-dosgi-ri-systests2</artifactId> - <version>1.8-SNAPSHOT</version> - <packaging>pom</packaging> - - <name>Distributed OSGi System Tests</name> - - <modules> - <module>common</module> - <module>multi-bundle</module> - </modules> -</project> http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/bnd.bnd ---------------------------------------------------------------------- diff --git a/topology-manager/bnd.bnd b/topology-manager/bnd.bnd new file mode 100644 index 0000000..3ff22e0 --- /dev/null +++ b/topology-manager/bnd.bnd @@ -0,0 +1 @@ +Bundle-Activator: org.apache.cxf.dosgi.topologymanager.Activator http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/pom.xml ---------------------------------------------------------------------- diff --git a/topology-manager/pom.xml b/topology-manager/pom.xml new file mode 100644 index 0000000..2df803e --- /dev/null +++ b/topology-manager/pom.xml @@ -0,0 +1,47 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<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/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.aries.rsa</groupId> + <artifactId>parent</artifactId> + <version>1.8-SNAPSHOT</version> + <relativePath>../parent/pom.xml</relativePath> + </parent> + + <artifactId>topology-manager</artifactId> + <packaging>bundle</packaging> + <name>Aries Remote Service Admin Topology Manager</name> + + <properties> + <topDirectoryLocation>..</topDirectoryLocation> + </properties> + + <dependencies> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-all</artifactId> + <version>1.3</version> + </dependency> + </dependencies> + +</project> http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java new file mode 100644 index 0000000..62ec1a9 --- /dev/null +++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java @@ -0,0 +1,192 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.dosgi.topologymanager; + +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.apache.cxf.dosgi.dsw.api.ExportPolicy; +import org.apache.cxf.dosgi.topologymanager.exporter.DefaultExportPolicy; +import org.apache.cxf.dosgi.topologymanager.exporter.EndpointListenerNotifier; +import org.apache.cxf.dosgi.topologymanager.exporter.EndpointRepository; +import org.apache.cxf.dosgi.topologymanager.exporter.TopologyManagerExport; +import org.apache.cxf.dosgi.topologymanager.importer.TopologyManagerImport; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Filter; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceEvent; +import org.osgi.framework.ServiceReference; +import org.osgi.service.remoteserviceadmin.EndpointListener; +import org.osgi.service.remoteserviceadmin.RemoteConstants; +import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Activator implements BundleActivator { + public static final String RSA_EXPORT_POLICY_FILTER = "rsa.export.policy.filter"; + static final String DOSGI_SERVICES = "(" + RemoteConstants.SERVICE_EXPORTED_INTERFACES + "=*)"; + private static final Logger LOG = LoggerFactory.getLogger(Activator.class); + + private TopologyManagerExport exportManager; + private TopologyManagerImport importManager; + private EndpointListenerNotifier notifier; + private ServiceTracker<RemoteServiceAdmin, RemoteServiceAdmin> rsaTracker; + private ThreadPoolExecutor exportExecutor; + private ServiceTracker<EndpointListener, EndpointListener> epListenerTracker; + private ServiceTracker<ExportPolicy, ExportPolicy> policyTracker; + + public void start(final BundleContext bc) throws Exception { + Dictionary<String, String> props = new Hashtable<String, String>(); + props.put("name", "default"); + bc.registerService(ExportPolicy.class, new DefaultExportPolicy(), props); + + Filter policyFilter = exportPolicyFilter(bc); + policyTracker = new ServiceTracker<ExportPolicy, ExportPolicy>(bc, policyFilter, null) { + + @Override + public ExportPolicy addingService(ServiceReference<ExportPolicy> reference) { + ExportPolicy policy = super.addingService(reference); + if (exportManager == null) { + doStart(bc, policy); + } + return policy; + } + + @Override + public void removedService(ServiceReference<ExportPolicy> reference, ExportPolicy service) { + if (exportManager != null) { + doStop(bc); + } + super.removedService(reference, service); + } + }; + policyTracker.open(); + } + + private Filter exportPolicyFilter(BundleContext bc) throws InvalidSyntaxException { + String filter = bc.getProperty(RSA_EXPORT_POLICY_FILTER); + if (filter == null) { + filter = "(name=default)"; + } + return FrameworkUtil.createFilter(String.format("(&(objectClass=%s)%s)", ExportPolicy.class.getName(), filter)); + } + + public void doStart(final BundleContext bc, ExportPolicy policy) { + LOG.debug("TopologyManager: start()"); + EndpointRepository endpointRepo = new EndpointRepository(); + notifier = new EndpointListenerNotifier(endpointRepo); + epListenerTracker = new EndpointListenerTracker(bc); + endpointRepo.setNotifier(notifier); + exportExecutor = new ThreadPoolExecutor(5, 10, 50, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); + exportManager = new TopologyManagerExport(endpointRepo, exportExecutor, policy); + importManager = new TopologyManagerImport(bc); + rsaTracker = new RSATracker(bc, RemoteServiceAdmin.class, null); + bc.addServiceListener(exportManager); + rsaTracker.open(); + epListenerTracker.open(); + exportExistingServices(bc); + importManager.start(); + } + + public void stop(BundleContext bc) throws Exception { + policyTracker.close(); + } + + public void doStop(BundleContext bc) { + LOG.debug("TopologyManager: stop()"); + epListenerTracker.close(); + bc.removeServiceListener(exportManager); + exportExecutor.shutdown(); + importManager.stop(); + rsaTracker.close(); + exportManager = null; + } + + public void exportExistingServices(BundleContext context) { + try { + // cast to String is necessary for compiling against OSGi core version >= 4.3 + ServiceReference<?>[] references = context.getServiceReferences((String)null, DOSGI_SERVICES); + if (references != null) { + for (ServiceReference<?> sref : references) { + exportManager.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, sref)); + } + } + } catch (InvalidSyntaxException e) { + LOG.error("Error in filter {}. This should not occur!", DOSGI_SERVICES); + } + } + + private final class EndpointListenerTracker extends ServiceTracker<EndpointListener, EndpointListener> { + private EndpointListenerTracker(BundleContext context) { + super(context, EndpointListener.class, null); + } + + @Override + public EndpointListener addingService(ServiceReference<EndpointListener> reference) { + EndpointListener listener = super.addingService(reference); + notifier.add(listener, EndpointListenerNotifier.getFiltersFromEndpointListenerScope(reference)); + return listener; + } + + @Override + public void modifiedService(ServiceReference<EndpointListener> reference, + EndpointListener listener) { + super.modifiedService(reference, listener); + notifier.add(listener, EndpointListenerNotifier.getFiltersFromEndpointListenerScope(reference)); + } + + @Override + public void removedService(ServiceReference<EndpointListener> reference, + EndpointListener listener) { + notifier.remove(listener); + super.removedService(reference, listener); + } + } + + private final class RSATracker extends ServiceTracker<RemoteServiceAdmin, RemoteServiceAdmin> { + private RSATracker(BundleContext context, Class<RemoteServiceAdmin> clazz, + ServiceTrackerCustomizer<RemoteServiceAdmin, RemoteServiceAdmin> customizer) { + super(context, clazz, customizer); + } + + @Override + public RemoteServiceAdmin addingService(ServiceReference<RemoteServiceAdmin> reference) { + RemoteServiceAdmin rsa = super.addingService(reference); + LOG.debug("New RemoteServiceAdmin {} detected, trying to import and export services with it", rsa); + importManager.add(rsa); + exportManager.add(rsa); + return rsa; + } + + @Override + public void removedService(ServiceReference<RemoteServiceAdmin> reference, + RemoteServiceAdmin rsa) { + exportManager.remove(rsa); + importManager.remove(rsa); + super.removedService(reference, rsa); + } + } +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/DefaultExportPolicy.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/DefaultExportPolicy.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/DefaultExportPolicy.java new file mode 100644 index 0000000..689ebab --- /dev/null +++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/DefaultExportPolicy.java @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.dosgi.topologymanager.exporter; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.cxf.dosgi.dsw.api.ExportPolicy; +import org.osgi.framework.ServiceReference; + +/** + * The default is to not customize the way services are exported + */ +public class DefaultExportPolicy implements ExportPolicy { + + @Override + public Map<String, ?> additionalParameters(ServiceReference<?> sref) { + return new HashMap<String, Object>(); + } + +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java new file mode 100644 index 0000000..13d7dab --- /dev/null +++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java @@ -0,0 +1,133 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.dosgi.topologymanager.exporter; + +import java.util.Dictionary; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.osgi.framework.Filter; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.service.remoteserviceadmin.EndpointDescription; +import org.osgi.service.remoteserviceadmin.EndpointListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Tracks EndpointListeners and allows to notify them of endpoints. + */ +public class EndpointListenerNotifier implements EndpointListener { + private static final Logger LOG = LoggerFactory.getLogger(EndpointListenerNotifier.class); + private enum NotifyType { ADDED, REMOVED }; + private Map<EndpointListener, Set<Filter>> listeners; + private EndpointRepository endpointRepo; + + public EndpointListenerNotifier(final EndpointRepository endpointRepo) { + this.endpointRepo = endpointRepo; + this.listeners = new ConcurrentHashMap<EndpointListener, Set<Filter>>(); + } + + public static Set<Filter> getFiltersFromEndpointListenerScope(ServiceReference<EndpointListener> sref) { + Set<Filter> filters = new HashSet<Filter>(); + String[] scopes = StringPlus.parse(sref.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE)); + for (String scope : scopes) { + try { + filters.add(FrameworkUtil.createFilter(scope)); + } catch (InvalidSyntaxException e) { + LOG.error("invalid endpoint listener scope: {}", scope, e); + } + } + return filters; + } + + public void add(EndpointListener ep, Set<Filter> filters) { + LOG.debug("new EndpointListener detected"); + listeners.put(ep, filters); + for (EndpointDescription endpoint : endpointRepo.getAllEndpoints()) { + notifyListener(NotifyType.ADDED, ep, filters, endpoint); + } + } + + public void remove(EndpointListener ep) { + LOG.debug("EndpointListener modified"); + listeners.remove(ep); + } + + @Override + public void endpointAdded(EndpointDescription endpoint, String matchedFilter) { + notifyListeners(NotifyType.ADDED, endpoint); + } + + @Override + public void endpointRemoved(EndpointDescription endpoint, String matchedFilter) { + notifyListeners(NotifyType.REMOVED, endpoint); + } + + /** + * Notifies all endpoint listeners about endpoints being added or removed. + * + * @param added specifies whether endpoints were added (true) or removed (false) + * @param endpoints the endpoints the listeners should be notified about + */ + private void notifyListeners(NotifyType type, EndpointDescription endpoint) { + for (EndpointListener listener : listeners.keySet()) { + notifyListener(type, listener, listeners.get(listener), endpoint); + } + } + + /** + * Notifies an endpoint listener about endpoints being added or removed. + * + * @param type specifies whether endpoints were added (true) or removed (false) + * @param endpointListenerRef the ServiceReference of an EndpointListener to notify + * @param endpoints the endpoints the listener should be notified about + */ + private void notifyListener(NotifyType type, EndpointListener listener, Set<Filter> filters, + EndpointDescription endpoint) { + LOG.debug("Endpoint {}", type); + Set<Filter> matchingFilters = getMatchingFilters(filters, endpoint); + for (Filter filter : matchingFilters) { + if (type == NotifyType.ADDED) { + listener.endpointAdded(endpoint, filter.toString()); + } else { + listener.endpointRemoved(endpoint, filter.toString()); + } + } + } + + private static Set<Filter> getMatchingFilters(Set<Filter> filters, EndpointDescription endpoint) { + Set<Filter> matchingFilters = new HashSet<Filter>(); + Dictionary<String, Object> dict = new Hashtable<String, Object>(endpoint.getProperties()); + for (Filter filter : filters) { + if (filter.match(dict)) { + LOG.debug("Filter {} matches endpoint {}", filter, dict); + matchingFilters.add(filter); + } else { + LOG.trace("Filter {} does not match endpoint {}", filter, dict); + } + } + return matchingFilters; + } + +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java new file mode 100644 index 0000000..2a7bab3 --- /dev/null +++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java @@ -0,0 +1,140 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.dosgi.topologymanager.exporter; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.osgi.framework.ServiceReference; +import org.osgi.service.remoteserviceadmin.EndpointDescription; +import org.osgi.service.remoteserviceadmin.EndpointListener; +import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Holds all endpoints that are exported by a TopologyManager. For each ServiceReference that is exported a + * map is maintained which contains information on the endpoints for each RemoteAdminService that created the + * endpoints. + */ +@SuppressWarnings("rawtypes") +public class EndpointRepository { + + private static final Logger LOG = LoggerFactory.getLogger(EndpointRepository.class); + + private final Map<ServiceReference, Map<RemoteServiceAdmin, Collection<EndpointDescription>>> exportedServices + = new LinkedHashMap<ServiceReference, Map<RemoteServiceAdmin, Collection<EndpointDescription>>>(); + + private EndpointListener notifier; + + public void setNotifier(EndpointListener notifier) { + this.notifier = notifier; + } + + + /** + * Remove all services exported by the given rsa. + * + * @param rsa the RemoteServiceAdmin to remove + * @return list of removed endpoints + */ + public synchronized List<EndpointDescription> removeRemoteServiceAdmin(RemoteServiceAdmin rsa) { + LOG.debug("RemoteServiceAdmin removed: {}", rsa.getClass().getName()); + List<EndpointDescription> removedEndpoints = new ArrayList<EndpointDescription>(); + for (Map<RemoteServiceAdmin, Collection<EndpointDescription>> exports : exportedServices.values()) { + Collection<EndpointDescription> endpoints = exports.get(rsa); + if (endpoints != null) { + removedEndpoints.addAll(endpoints); + exports.remove(rsa); + } + } + endpointsRemoved(removedEndpoints); + return removedEndpoints; + } + + public synchronized void removeService(ServiceReference sref) { + List<EndpointDescription> removedEndpoints = new ArrayList<EndpointDescription>(); + Map<RemoteServiceAdmin, Collection<EndpointDescription>> rsaToEndpoints = exportedServices.get(sref); + if (rsaToEndpoints != null) { + for (Collection<EndpointDescription> endpoints : rsaToEndpoints.values()) { + removedEndpoints.addAll(endpoints); + } + exportedServices.remove(sref); + } + endpointsRemoved(removedEndpoints); + } + + public synchronized void addService(ServiceReference sref) { + if (!exportedServices.containsKey(sref)) { + LOG.info("Marking service from bundle {} for export", sref.getBundle().getSymbolicName()); + exportedServices.put(sref, new LinkedHashMap<RemoteServiceAdmin, Collection<EndpointDescription>>()); + } + } + + public synchronized void addEndpoints(ServiceReference sref, RemoteServiceAdmin rsa, + List<EndpointDescription> endpoints) { + addService(sref); + Map<RemoteServiceAdmin, Collection<EndpointDescription>> exports = exportedServices.get(sref); + exports.put(rsa, endpoints); + endpointsAdded(endpoints); + } + + synchronized boolean isAlreadyExportedForRsa(ServiceReference sref, RemoteServiceAdmin rsa) { + Map<RemoteServiceAdmin, Collection<EndpointDescription>> exports = exportedServices.get(sref); + return exports != null && exports.containsKey(rsa); + } + + public synchronized Collection<EndpointDescription> getAllEndpoints() { + List<EndpointDescription> allEndpoints = new ArrayList<EndpointDescription>(); + for (Map<RemoteServiceAdmin, Collection<EndpointDescription>> exports : exportedServices.values()) { + for (Collection<EndpointDescription> endpoints : exports.values()) { + allEndpoints.addAll(endpoints); + } + } + return allEndpoints; + } + + public synchronized Set<ServiceReference> getServicesToBeExportedFor(RemoteServiceAdmin rsa) { + Set<ServiceReference> servicesToBeExported = new HashSet<ServiceReference>(); + for (Map.Entry<ServiceReference, Map<RemoteServiceAdmin, Collection<EndpointDescription>>> entry + : exportedServices.entrySet()) { + if (!entry.getValue().containsKey(rsa)) { + servicesToBeExported.add(entry.getKey()); + } + } + return servicesToBeExported; + } + + private void endpointsAdded(List<EndpointDescription> endpoints) { + for (EndpointDescription epd : endpoints) { + notifier.endpointAdded(epd, null); + } + } + + private void endpointsRemoved(List<EndpointDescription> endpoints) { + for (EndpointDescription epd : endpoints) { + notifier.endpointRemoved(epd, null); + } + } +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/StringPlus.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/StringPlus.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/StringPlus.java new file mode 100644 index 0000000..1198154 --- /dev/null +++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/StringPlus.java @@ -0,0 +1,57 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.dosgi.topologymanager.exporter; + +import java.util.Collection; + +public final class StringPlus { + + private StringPlus() { + } + + /** + * Returns the value of a "string+" property as an array of strings. + * <p> + * A "string+" property can have a value which is either a string, + * an array of strings, or a collection of strings. + * <p> + * If the given value is not of one of the valid types, or is null, + * an empty array is returned. + * + * @param property a "string+" property value + * @return the property value as an array of strings, or an empty array + */ + public static String[] parse(Object property) { + if (property instanceof String) { + return new String[] {(String)property}; + } else if (property instanceof String[]) { + return (String[])property; + } else if (property instanceof Collection) { + try { + @SuppressWarnings("unchecked") + Collection<String> strings = (Collection<String>)property; + return strings.toArray(new String[strings.size()]); + } catch (ArrayStoreException ase) { + // ignore collections with wrong type + } + } + return new String[0]; + } + +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java new file mode 100644 index 0000000..ad3736c --- /dev/null +++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java @@ -0,0 +1,195 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.dosgi.topologymanager.exporter; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; + +import org.apache.cxf.dosgi.dsw.api.ExportPolicy; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceEvent; +import org.osgi.framework.ServiceListener; +import org.osgi.framework.ServiceReference; +import org.osgi.service.remoteserviceadmin.EndpointDescription; +import org.osgi.service.remoteserviceadmin.ExportReference; +import org.osgi.service.remoteserviceadmin.ExportRegistration; +import org.osgi.service.remoteserviceadmin.RemoteConstants; +import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Manages exported endpoints of DOSGi services and notifies EndpointListeners of changes. + * + * <li> Tracks local RemoteServiceAdmin instances by using a ServiceTracker + * <li> Uses a ServiceListener to track local OSGi services + * <li> When a service is published that is supported by DOSGi the + * known RemoteServiceAdmins are instructed to export the service and + * the EndpointListeners are notified + * <li> When a service is unpublished the EndpointListeners are notified. + * The endpoints are not closed as the ExportRegistration takes care of this + */ +public class TopologyManagerExport implements ServiceListener { + private static final Logger LOG = LoggerFactory.getLogger(TopologyManagerExport.class); + + private final Executor execService; + private final EndpointRepository endpointRepo; + private ExportPolicy policy; + private final Set<RemoteServiceAdmin> rsaSet; + + + public TopologyManagerExport(final EndpointRepository endpointRepo, Executor executor, ExportPolicy policy) { + this.endpointRepo = endpointRepo; + this.policy = policy; + this.rsaSet = new HashSet<RemoteServiceAdmin>(); + this.execService = executor; + } + + // track all service registrations so we can export any services that are configured to be exported + // ServiceListener events may be delivered out of order, concurrently, re-entrant, etc. (see spec or docs) + public void serviceChanged(ServiceEvent event) { + ServiceReference<?> sref = event.getServiceReference(); + if (event.getType() == ServiceEvent.REGISTERED) { + LOG.debug("Received REGISTERED ServiceEvent: {}", event); + export(sref); + } else if (event.getType() == ServiceEvent.UNREGISTERING) { + LOG.debug("Received UNREGISTERING ServiceEvent: {}", event); + endpointRepo.removeService(sref); + } + } + + public void add(RemoteServiceAdmin rsa) { + rsaSet.add(rsa); + for (ServiceReference<?> serviceRef : endpointRepo.getServicesToBeExportedFor(rsa)) { + export(serviceRef); + } + }; + + public void remove(RemoteServiceAdmin rsa) { + rsaSet.remove(rsa); + endpointRepo.removeRemoteServiceAdmin(rsa); + }; + + private void export(final ServiceReference<?> sref) { + execService.execute(new Runnable() { + public void run() { + doExport(sref); + } + }); + } + + private void doExport(final ServiceReference<?> sref) { + Map<String, ?> addProps = policy.additionalParameters(sref); + if (!shouldExport(sref, addProps)) { + LOG.debug("Skipping service {}", sref); + return; + } + LOG.debug("Exporting service {}", sref); + endpointRepo.addService(sref); // mark for future export even if there are currently no RSAs + if (rsaSet.size() == 0) { + LOG.error("No RemoteServiceAdmin available! Unable to export service from bundle {}, interfaces: {}", + getSymbolicName(sref.getBundle()), + sref.getProperty(org.osgi.framework.Constants.OBJECTCLASS)); + return; + } + + for (RemoteServiceAdmin remoteServiceAdmin : rsaSet) { + LOG.info("TopologyManager: handling remoteServiceAdmin " + remoteServiceAdmin); + if (endpointRepo.isAlreadyExportedForRsa(sref, remoteServiceAdmin)) { + // already handled by this remoteServiceAdmin + LOG.debug("already handled by this remoteServiceAdmin -> skipping"); + } else { + + exportServiceUsingRemoteServiceAdmin(sref, remoteServiceAdmin, addProps); + } + } + } + + private boolean shouldExport(ServiceReference<?> sref, Map<String, ?> addProps) { + String exported = (String)sref.getProperty(RemoteConstants.SERVICE_EXPORTED_INTERFACES); + String addExported = (String)addProps.get(RemoteConstants.SERVICE_EXPORTED_INTERFACES); + String effectiveExported = addExported != null ? addExported : exported; + return (effectiveExported != null) && !effectiveExported.isEmpty(); + } + + private Object getSymbolicName(Bundle bundle) { + return bundle == null ? null : bundle.getSymbolicName(); + } + + private void exportServiceUsingRemoteServiceAdmin(final ServiceReference<?> sref, + final RemoteServiceAdmin remoteServiceAdmin, + Map<String, ?> addProps) { + // abort if the service was unregistered by the time we got here + // (we check again at the end, but this optimization saves unnecessary heavy processing) + if (sref.getBundle() == null) { + LOG.info("TopologyManager: export aborted for {} since it was unregistered", sref); + endpointRepo.removeService(sref); + return; + } + // do the export + LOG.debug("exporting {}...", sref); + // TODO: additional parameter Map? + Collection<ExportRegistration> exportRegs = remoteServiceAdmin.exportService(sref, addProps); + // process successful/failed registrations + List<EndpointDescription> endpoints = new ArrayList<EndpointDescription>(); + for (ExportRegistration reg : exportRegs) { + if (reg.getException() == null) { + EndpointDescription endpoint = getExportedEndpoint(reg); + LOG.info("TopologyManager: export succeeded for {}, endpoint ", sref, endpoint); + endpoints.add(endpoint); + } else { + LOG.error("TopologyManager: export failed for {}", sref); + reg.close(); + } + } + // abort export if service was unregistered in the meanwhile (since we have a race + // with the unregister event which may have already been handled, so we'll miss it) + if (sref.getBundle() == null) { + LOG.info("TopologyManager: export reverted for {} since service was unregistered", sref); + endpointRepo.removeService(sref); + for (ExportRegistration reg : exportRegs) { + reg.close(); + } + return; + } + // add the new exported endpoints + if (!endpoints.isEmpty()) { + LOG.info("TopologyManager: export successful for {}, endpoints: {}", sref, endpoints); + endpointRepo.addEndpoints(sref, remoteServiceAdmin, endpoints); + } + } + + /** + * Retrieves an exported Endpoint (while safely handling nulls). + * + * @param exReg an export registration + * @return exported Endpoint or null if not present + */ + private EndpointDescription getExportedEndpoint(ExportRegistration exReg) { + ExportReference ref = (exReg == null) ? null : exReg.getExportReference(); + return (ref == null) ? null : ref.getExportedEndpoint(); + } + + +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java new file mode 100644 index 0000000..7812e52 --- /dev/null +++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.dosgi.topologymanager.importer; + +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.remoteserviceadmin.EndpointListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Manages an EndpointListener and adjusts its scope according to requested service filters. + */ +public class EndpointListenerManager { + + private static final Logger LOG = LoggerFactory.getLogger(EndpointListenerManager.class); + + private final BundleContext bctx; + private volatile ServiceRegistration<EndpointListener> serviceRegistration; + private final List<String> filters = new ArrayList<String>(); + private final EndpointListener endpointListener; + + public EndpointListenerManager(BundleContext bc, EndpointListener endpointListener) { + this.bctx = bc; + this.endpointListener = endpointListener; + } + + protected void start() { + serviceRegistration = bctx.registerService(EndpointListener.class, endpointListener, + getRegistrationProperties()); + } + + public void stop() { + if (serviceRegistration != null) { + serviceRegistration.unregister(); + } + } + + protected void extendScope(String filter) { + if (filter == null) { + return; + } + LOG.debug("EndpointListener: extending scope by {}", filter); + synchronized (filters) { + filters.add(filter); + } + updateRegistration(); + } + + protected void reduceScope(String filter) { + if (filter == null) { + return; + } + LOG.debug("EndpointListener: reducing scope by {}", filter); + synchronized (filters) { + filters.remove(filter); + } + updateRegistration(); + } + + private Dictionary<String, Object> getRegistrationProperties() { + Dictionary<String, Object> p = new Hashtable<String, Object>(); + + synchronized (filters) { + LOG.debug("Current filter: {}", filters); + p.put(EndpointListener.ENDPOINT_LISTENER_SCOPE, new ArrayList<String>(filters)); + } + + return p; + } + + private void updateRegistration() { + if (serviceRegistration != null) { + serviceRegistration.setProperties(getRegistrationProperties()); + } + } +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/FilterHelper.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/FilterHelper.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/FilterHelper.java new file mode 100644 index 0000000..3739f16 --- /dev/null +++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/FilterHelper.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.dosgi.topologymanager.importer; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.osgi.framework.Constants; + +public final class FilterHelper { + private static final String OBJECTCLASS_EXPRESSION = ".*\\(" + Constants.OBJECTCLASS + "=([a-zA-Z_0-9.]+)\\).*"; + private static final Pattern OBJECTCLASS_PATTERN = Pattern.compile(OBJECTCLASS_EXPRESSION); + + private FilterHelper() { + // prevent instantiation + } + + public static String getObjectClass(String filter) { + if (filter != null) { + Matcher matcher = OBJECTCLASS_PATTERN.matcher(filter); + if (matcher.matches() && matcher.groupCount() >= 1) { + return matcher.group(1); + } + } + return null; + } +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java new file mode 100644 index 0000000..03ec9da --- /dev/null +++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java @@ -0,0 +1,119 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.dosgi.topologymanager.importer; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.hooks.service.ListenerHook; +import org.osgi.service.remoteserviceadmin.RemoteConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Listens for service listeners and informs ServiceInterestListener about added and removed interest + * in services + */ +public class ListenerHookImpl implements ListenerHook { + + private static final Logger LOG = LoggerFactory.getLogger(ListenerHookImpl.class); + + // From the old impl. + private static final Set<String> SYSTEM_PACKAGES; + static { + SYSTEM_PACKAGES = new HashSet<String>(); + SYSTEM_PACKAGES.add("org.osgi.service"); + SYSTEM_PACKAGES.add("org.apache.felix"); + SYSTEM_PACKAGES.add("org.ops4j.pax.logging"); + SYSTEM_PACKAGES.add("ch.ethz.iks.slp"); + SYSTEM_PACKAGES.add("org.ungoverned.osgi.service"); + SYSTEM_PACKAGES.add("org.springframework.osgi.context.event.OsgiBundleApplicationContextListener"); + SYSTEM_PACKAGES.add("java.net.ContentHandler"); + } + + private final BundleContext bctx; + private final ServiceInterestListener serviceInterestListener; + private final String frameworkUUID; + + public ListenerHookImpl(BundleContext bc, ServiceInterestListener serviceInterestListener) { + this.bctx = bc; + this.frameworkUUID = bctx.getProperty(Constants.FRAMEWORK_UUID); + this.serviceInterestListener = serviceInterestListener; + } + + @Override + public void added(Collection<ListenerInfo> listeners) { + LOG.debug("added listeners {}", listeners); + for (ListenerInfo listenerInfo : listeners) { + LOG.debug("Filter {}", listenerInfo.getFilter()); + + String className = FilterHelper.getObjectClass(listenerInfo.getFilter()); + + if (listenerInfo.getBundleContext().equals(bctx)) { + LOG.debug("ListenerHookImpl: skipping request from myself"); + continue; + } + + if (listenerInfo.getFilter() == null) { + LOG.debug("skipping empty filter"); + continue; + } + + if (isClassExcluded(className)) { + LOG.debug("Skipping import request for excluded class [{}]", className); + continue; + } + String exFilter = extendFilter(listenerInfo.getFilter()); + serviceInterestListener.addServiceInterest(exFilter); + } + } + + @Override + public void removed(Collection<ListenerInfo> listeners) { + LOG.debug("removed listeners {}", listeners); + + for (ListenerInfo listenerInfo : listeners) { + LOG.debug("Filter {}", listenerInfo.getFilter()); + + // TODO: determine if service was handled? + String exFilter = extendFilter(listenerInfo.getFilter()); + serviceInterestListener.removeServiceInterest(exFilter); + } + } + + private static boolean isClassExcluded(String className) { + if (className == null) { + return true; + } + + for (String p : SYSTEM_PACKAGES) { + if (className.startsWith(p)) { + return true; + } + } + return false; + } + + String extendFilter(String filter) { + return "(&" + filter + "(!(" + RemoteConstants.ENDPOINT_FRAMEWORK_UUID + "=" + frameworkUUID + ")))"; + } +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/RSATracker.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/RSATracker.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/RSATracker.java new file mode 100644 index 0000000..56e98e8 --- /dev/null +++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/RSATracker.java @@ -0,0 +1,26 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.dosgi.topologymanager.importer; + +import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin; + +public interface RSATracker { + void added(RemoteServiceAdmin rsa); + void removed(RemoteServiceAdmin rsa); +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ReferenceCounter.java ---------------------------------------------------------------------- diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ReferenceCounter.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ReferenceCounter.java new file mode 100644 index 0000000..6ecff31 --- /dev/null +++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ReferenceCounter.java @@ -0,0 +1,76 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.dosgi.topologymanager.importer; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * Manages a reference count per key. + * + * @param <K> the key type + */ +public class ReferenceCounter<K> { + + private final ConcurrentMap<K, Integer> counts = new ConcurrentHashMap<K, Integer>(); + + /** + * Increases the reference count for the given key, + * or sets it to 1 if the key has no existing count. + * + * @param key a key + * @return the updated reference count + */ + public int add(K key) { + while (true) { + Integer count = counts.get(key); + if (count == null) { + if (counts.putIfAbsent(key, 1) == null) { + return 1; + } + } else if (counts.replace(key, count, count + 1)) { + return count + 1; + } + } + } + + /** + * Decreases the reference count for the given key, + * and removes it if it reaches 0. + * If the key has no existing count, -1 is returned. + * + * @param key a key + * @return the updated reference count, or -1 if the key has no existing count + */ + public int remove(K key) { + while (true) { + Integer count = counts.get(key); + if (count == null) { + return -1; + } + if (count == 1) { + if (counts.remove(key, 1)) { + return 0; + } + } else if (counts.replace(key, count, count - 1)) { + return count - 1; + } + } + } +}
