You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by cs...@apache.org on 2016/07/01 19:57:00 UTC
[3/3] cxf-dosgi git commit: [DOSGI-242] Extract common module, use DS
[DOSGI-242] Extract common module, use DS
Project: http://git-wip-us.apache.org/repos/asf/cxf-dosgi/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf-dosgi/commit/d2a3c75f
Tree: http://git-wip-us.apache.org/repos/asf/cxf-dosgi/tree/d2a3c75f
Diff: http://git-wip-us.apache.org/repos/asf/cxf-dosgi/diff/d2a3c75f
Branch: refs/heads/master
Commit: d2a3c75f3a6496ec52961ee7238fcf519bd9a8a5
Parents: 79bb9a4
Author: Christian Schneider <ch...@die-schneider.net>
Authored: Fri Jul 1 21:56:50 2016 +0200
Committer: Christian Schneider <ch...@die-schneider.net>
Committed: Fri Jul 1 21:56:50 2016 +0200
----------------------------------------------------------------------
common/bnd.bnd | 6 +
common/pom.xml | 78 +++++
.../common/httpservice/HttpServiceManager.java | 179 ++++++++++++
.../dosgi/common/httpservice/LocalHostUtil.java | 92 ++++++
.../SecurityDelegatingHttpContext.java | 133 +++++++++
.../common/intent/DefaultIntentMapFactory.java | 52 ++++
.../cxf/dosgi/common/intent/IntentManager.java | 35 +++
.../dosgi/common/intent/IntentManagerImpl.java | 214 ++++++++++++++
.../cxf/dosgi/common/intent/IntentMap.java | 62 ++++
.../cxf/dosgi/common/intent/IntentTracker.java | 61 ++++
.../cxf/dosgi/common/util/ClassUtils.java | 86 ++++++
.../apache/cxf/dosgi/common/util/OsgiUtils.java | 78 +++++
.../cxf/dosgi/common/util/ServerWrapper.java | 49 ++++
.../cxf/dosgi/common/util/StringPlus.java | 72 +++++
.../httpservice/HttpServiceManagerTest.java | 118 ++++++++
.../SecurityDelegatingHttpContextTest.java | 267 ++++++++++++++++++
.../dosgi/common/qos/IntentManagerImplTest.java | 282 +++++++++++++++++++
.../cxf/dosgi/common/qos/IntentMapTest.java | 42 +++
.../cxf/dosgi/common/qos/IntentTrackerTest.java | 82 ++++++
.../cxf/dosgi/common/util/ClassUtilsTest.java | 114 ++++++++
.../cxf/dosgi/common/util/OsgiUtilsTest.java | 70 +++++
.../apache/cxf/dosgi/common/util/Provider.java | 23 ++
cxf-dsw/bnd.bnd | 3 +-
cxf-dsw/pom.xml | 6 +
.../dsw/handlers/CXFDistributionProvider.java | 71 ++++-
.../AbstractPojoConfigurationTypeHandler.java | 36 ++-
.../pojo/PojoConfigurationTypeHandler.java | 4 +-
.../pojo/WsdlConfigurationTypeHandler.java | 6 +-
.../rest/JaxRSPojoConfigurationTypeHandler.java | 8 +-
.../cxf/dosgi/dsw/handlers/rest/JaxRSUtils.java | 4 +-
.../dsw/httpservice/HttpServiceManager.java | 176 ------------
.../dosgi/dsw/httpservice/LocalHostUtil.java | 92 ------
.../SecurityDelegatingHttpContext.java | 133 ---------
.../apache/cxf/dosgi/dsw/osgi/Activator.java | 153 ----------
.../apache/cxf/dosgi/dsw/osgi/Constants.java | 70 +----
.../dosgi/dsw/qos/DefaultIntentMapFactory.java | 52 ----
.../apache/cxf/dosgi/dsw/qos/IntentManager.java | 31 --
.../cxf/dosgi/dsw/qos/IntentManagerImpl.java | 155 ----------
.../org/apache/cxf/dosgi/dsw/qos/IntentMap.java | 62 ----
.../apache/cxf/dosgi/dsw/qos/IntentTracker.java | 62 ----
.../apache/cxf/dosgi/dsw/qos/IntentUtils.java | 86 ------
.../apache/cxf/dosgi/dsw/util/ClassUtils.java | 86 ------
.../apache/cxf/dosgi/dsw/util/OsgiUtils.java | 78 -----
.../cxf/dosgi/dsw/util/ServerWrapper.java | 49 ----
.../apache/cxf/dosgi/dsw/util/StringPlus.java | 72 -----
.../org/apache/cxf/dosgi/dsw/ActivatorTest.java | 67 -----
.../org/apache/cxf/dosgi/dsw/TestUtils.java | 37 ---
.../handlers/CXFDistributionProviderTest.java | 22 +-
.../cxf/dosgi/dsw/handlers/ClassUtilsTest.java | 116 --------
.../pojo/PojoConfigurationTypeHandlerTest.java | 35 ++-
.../dsw/httpservice/HttpServiceManagerTest.java | 125 --------
.../SecurityDelegatingHttpContextTest.java | 267 ------------------
.../dosgi/dsw/qos/IntentManagerImplTest.java | 278 ------------------
.../apache/cxf/dosgi/dsw/qos/IntentMapTest.java | 41 ---
.../cxf/dosgi/dsw/qos/IntentTrackerTest.java | 80 ------
.../cxf/dosgi/dsw/qos/IntentUtilsTest.java | 70 -----
.../cxf/dosgi/dsw/util/OsgiUtilsTest.java | 70 -----
.../org/apache/cxf/dosgi/dsw/util/Provider.java | 23 --
.../features/src/main/resources/features.xml | 6 +-
pom.xml | 1 +
60 files changed, 2346 insertions(+), 2582 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/bnd.bnd
----------------------------------------------------------------------
diff --git a/common/bnd.bnd b/common/bnd.bnd
new file mode 100644
index 0000000..9fc9a8c
--- /dev/null
+++ b/common/bnd.bnd
@@ -0,0 +1,6 @@
+Import-Package: javax.servlet;version='[2,4)', javax.servlet.http;version='[2,4)', *
+Export-Package: \
+ org.apache.cxf.dosgi.common.httpservice,\
+ org.apache.cxf.dosgi.common.util,\
+ org.apache.cxf.dosgi.common.intent
+Private-Package: org.apache.cxf.dosgi.common.osgi
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/pom.xml
----------------------------------------------------------------------
diff --git a/common/pom.xml b/common/pom.xml
new file mode 100644
index 0000000..dd5ea46
--- /dev/null
+++ b/common/pom.xml
@@ -0,0 +1,78 @@
+<?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>
+ <artifactId>cxf-dosgi-ri-common</artifactId>
+ <packaging>bundle</packaging>
+ <name>CXF dOSGi Common</name>
+
+ <parent>
+ <groupId>org.apache.cxf.dosgi</groupId>
+ <artifactId>cxf-dosgi-ri-parent</artifactId>
+ <version>1.9-SNAPSHOT</version>
+ <relativePath>../parent/pom.xml</relativePath>
+ </parent>
+
+ <properties>
+ <topDirectoryLocation>..</topDirectoryLocation>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-core</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-frontend-jaxws</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-client</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-databinding-aegis</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-extension-providers</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-servlet_${servlet.version}_spec</artifactId>
+ <version>1.0</version>
+ </dependency>
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/main/java/org/apache/cxf/dosgi/common/httpservice/HttpServiceManager.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/cxf/dosgi/common/httpservice/HttpServiceManager.java b/common/src/main/java/org/apache/cxf/dosgi/common/httpservice/HttpServiceManager.java
new file mode 100644
index 0000000..b129514
--- /dev/null
+++ b/common/src/main/java/org/apache/cxf/dosgi/common/httpservice/HttpServiceManager.java
@@ -0,0 +1,179 @@
+/**
+ * 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.common.httpservice;
+
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.transport.http.DestinationRegistry;
+import org.apache.cxf.transport.http.DestinationRegistryImpl;
+import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(
+ configurationPid = "cxf-dsw",
+ service = HttpServiceManager.class
+ )
+public class HttpServiceManager {
+ /**
+ * Prefix to create an absolute URL from a relative URL.
+ * See HttpServiceManager.getAbsoluteAddress
+ *
+ * Defaults to: http://<host name>:8181
+ */
+ public static final String KEY_HTTP_BASE = "httpBase";
+ public static final String KEY_CXF_SERVLET_ALIAS = "cxfServletAlias";
+ public static final String DEFAULT_CXF_SERVLET_ALIAS = "/cxf";
+ private static final Logger LOG = LoggerFactory.getLogger(HttpServiceManager.class);
+
+ private Map<Long, String> exportedAliases = Collections.synchronizedMap(new HashMap<Long, String>());
+ private String httpBase;
+ private String cxfServletAlias;
+ private HttpService httpService;
+ private BundleContext context;
+
+ @SuppressWarnings("unchecked")
+ @Activate
+ public void activate(ComponentContext compContext) {
+ Dictionary<String, String> config = compContext.getProperties();
+ initFromConfig(config);
+ this.context = compContext.getBundleContext();
+ }
+
+ void initFromConfig(Dictionary<String, String> config) {
+ if (config == null) {
+ config = new Hashtable<String, String>();
+ }
+ this.httpBase = getWithDefault(config.get(KEY_HTTP_BASE), "http://" + LocalHostUtil.getLocalIp() + ":8181");
+ this.cxfServletAlias = getWithDefault(config.get(KEY_CXF_SERVLET_ALIAS), "/cxf");
+ }
+
+ private String getWithDefault(String value, String defaultValue) {
+ return value == null ? defaultValue : value;
+ }
+
+ public Bus registerServlet(Bus bus, String contextRoot, BundleContext callingContext, Long sid) {
+ bus.setExtension(new DestinationRegistryImpl(), DestinationRegistry.class);
+ CXFNonSpringServlet cxf = new CXFNonSpringServlet();
+ cxf.setBus(bus);
+ try {
+ HttpContext httpContext1 = httpService.createDefaultHttpContext();
+ HttpContext httpContext = new SecurityDelegatingHttpContext(callingContext, httpContext1);
+ httpService.registerServlet(contextRoot, cxf, new Hashtable<String, String>(),
+ httpContext);
+
+ registerUnexportHook(sid, contextRoot);
+
+ LOG.info("Successfully registered CXF DOSGi servlet at " + contextRoot);
+ } catch (Exception e) {
+ throw new ServiceException("CXF DOSGi: problem registering CXF HTTP Servlet", e);
+ }
+ return bus;
+ }
+
+ /**
+ * This listens for service removal events and "un-exports" the service
+ * from the HttpService.
+ *
+ * @param sref the service reference to track
+ * @param alias the HTTP servlet context alias
+ */
+ private void registerUnexportHook(Long sid, String alias) {
+ LOG.debug("Registering service listener for service with ID {}", sid);
+
+ String previous = exportedAliases.put(sid, alias);
+ if (previous != null) {
+ LOG.warn("Overwriting service export for service with ID {}", sid);
+ }
+
+ try {
+ Filter f = context.createFilter("(" + org.osgi.framework.Constants.SERVICE_ID + "=" + sid + ")");
+ if (f != null) {
+ context.addServiceListener(new UnregisterListener(), f.toString());
+ } else {
+ LOG.warn("Service listener could not be started. The service will not be automatically unexported.");
+ }
+ } catch (InvalidSyntaxException e) {
+ LOG.warn("Service listener could not be started. The service will not be automatically unexported.", e);
+ }
+ }
+
+ public String getDefaultAddress(Class<?> type) {
+ return "/" + type.getName().replace('.', '/');
+ }
+
+ public String getAbsoluteAddress(String contextRoot, String relativeEndpointAddress) {
+ if (relativeEndpointAddress.startsWith("http")) {
+ return relativeEndpointAddress;
+ }
+ String effContextRoot = contextRoot == null ? cxfServletAlias : contextRoot;
+ return this.httpBase + effContextRoot + relativeEndpointAddress;
+ }
+
+ private final class UnregisterListener implements ServiceListener {
+
+ public void serviceChanged(ServiceEvent event) {
+ if (!(event.getType() == ServiceEvent.UNREGISTERING)) {
+ return;
+ }
+ final ServiceReference<?> sref = event.getServiceReference();
+ final Long sid = (Long) sref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
+ final String alias = exportedAliases.remove(sid);
+ if (alias == null) {
+ LOG.error("Unable to unexport HTTP servlet for service class '{}',"
+ + " service-id {}: no servlet alias found",
+ sref.getProperty(org.osgi.framework.Constants.OBJECTCLASS), sid);
+ return;
+ }
+ LOG.debug("Unexporting HTTP servlet for alias '{}'", alias);
+ try {
+ httpService.unregister(alias);
+ } catch (Exception e) {
+ LOG.warn("An exception occurred while unregistering service for HTTP servlet alias '{}'", alias, e);
+ }
+ }
+ }
+
+ public void setContext(BundleContext context) {
+ this.context = context;
+ }
+
+ @Reference
+ public void setHttpService(HttpService httpService) {
+ this.httpService = httpService;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/main/java/org/apache/cxf/dosgi/common/httpservice/LocalHostUtil.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/cxf/dosgi/common/httpservice/LocalHostUtil.java b/common/src/main/java/org/apache/cxf/dosgi/common/httpservice/LocalHostUtil.java
new file mode 100644
index 0000000..0ac245d
--- /dev/null
+++ b/common/src/main/java/org/apache/cxf/dosgi/common/httpservice/LocalHostUtil.java
@@ -0,0 +1,92 @@
+/**
+ * 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.common.httpservice;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+/**
+ * Utility methods to get the local address even on a linux host.
+ */
+final class LocalHostUtil {
+
+ private LocalHostUtil() {
+ // Util Class
+ }
+
+ /**
+ * Returns an InetAddress representing the address of the localhost. Every
+ * attempt is made to find an address for this host that is not the loopback
+ * address. If no other address can be found, the loopback will be returned.
+ *
+ * @return InetAddress the address of localhost
+ * @throws UnknownHostException if there is a problem determining the address
+ */
+ public static InetAddress getLocalHost() throws UnknownHostException {
+ InetAddress localHost = InetAddress.getLocalHost();
+ if (!localHost.isLoopbackAddress()) {
+ return localHost;
+ }
+ InetAddress[] addrs = getAllLocalUsingNetworkInterface();
+ for (InetAddress addr : addrs) {
+ if (!addr.isLoopbackAddress() && !addr.getHostAddress().contains(":")) {
+ return addr;
+ }
+ }
+ return localHost;
+ }
+
+ /**
+ * Utility method that delegates to the methods of NetworkInterface to
+ * determine addresses for this machine.
+ *
+ * @return all addresses found from the NetworkInterfaces
+ * @throws UnknownHostException if there is a problem determining addresses
+ */
+ private static InetAddress[] getAllLocalUsingNetworkInterface() throws UnknownHostException {
+ try {
+ List<InetAddress> addresses = new ArrayList<InetAddress>();
+ Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
+ while (e.hasMoreElements()) {
+ NetworkInterface ni = e.nextElement();
+ for (Enumeration<InetAddress> e2 = ni.getInetAddresses(); e2.hasMoreElements();) {
+ addresses.add(e2.nextElement());
+ }
+ }
+ return addresses.toArray(new InetAddress[] {});
+ } catch (SocketException ex) {
+ throw new UnknownHostException("127.0.0.1");
+ }
+ }
+
+ public static String getLocalIp() {
+ String localIP;
+ try {
+ localIP = getLocalHost().getHostAddress();
+ } catch (Exception e) {
+ localIP = "localhost";
+ }
+ return localIP;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/main/java/org/apache/cxf/dosgi/common/httpservice/SecurityDelegatingHttpContext.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/cxf/dosgi/common/httpservice/SecurityDelegatingHttpContext.java b/common/src/main/java/org/apache/cxf/dosgi/common/httpservice/SecurityDelegatingHttpContext.java
new file mode 100644
index 0000000..4eba758
--- /dev/null
+++ b/common/src/main/java/org/apache/cxf/dosgi/common/httpservice/SecurityDelegatingHttpContext.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.common.httpservice;
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <p>
+ * An HttpContext that delegates to another HttpContext for all things other than security. This implementation handles
+ * security by delegating to a {@link FilterChain} based on the set of {@link Filter}s registered with a
+ * {@link #FILTER_PROP} property.
+ * </p>
+ * <p>
+ * If the {@link BundleContext} contains a {@link #FILTER_REQUIRED_PROP} property with value "true", requests will not
+ * be allowed until at least one {@link Filter} with a {@link #FILTER_PROP} property is registered.
+ * </p>
+ */
+class SecurityDelegatingHttpContext implements HttpContext {
+
+ public static final String FILTER_PROP = "org.apache.cxf.httpservice.filter";
+ public static final String FILTER_REQUIRED_PROP = "org.apache.cxf.httpservice.requirefilter";
+ private static final Logger LOG = LoggerFactory.getLogger(SecurityDelegatingHttpContext.class);
+ private static final String FILTER_FILTER = "(" + FILTER_PROP + "=*)";
+
+ BundleContext bundleContext;
+ HttpContext delegate;
+ boolean requireFilter;
+
+ SecurityDelegatingHttpContext(BundleContext bundleContext, HttpContext delegate) {
+ this.bundleContext = bundleContext;
+ this.delegate = delegate;
+ requireFilter = Boolean.TRUE.toString().equalsIgnoreCase(bundleContext.getProperty(FILTER_REQUIRED_PROP));
+ }
+
+ public String getMimeType(String name) {
+ return delegate.getMimeType(name);
+ }
+
+ public URL getResource(String name) {
+ return delegate.getResource(name);
+ }
+
+ @SuppressWarnings({
+ "unchecked", "rawtypes"
+ })
+ public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ ServiceReference[] refs;
+ try {
+ refs = bundleContext.getServiceReferences(Filter.class.getName(), FILTER_FILTER);
+ } catch (InvalidSyntaxException e) {
+ LOG.warn(e.getMessage(), e);
+ return false;
+ }
+ if (refs == null || refs.length == 0) {
+ LOG.info("No filter registered.");
+ return !requireFilter;
+ }
+ Filter[] filters = new Filter[refs.length];
+ try {
+ for (int i = 0; i < refs.length; i++) {
+ filters[i] = (Filter)bundleContext.getService(refs[i]);
+ }
+ try {
+ new Chain(filters).doFilter(request, response);
+ return !response.isCommitted();
+ } catch (ServletException e) {
+ LOG.warn(e.getMessage(), e);
+ return false;
+ }
+ } finally {
+ for (int i = 0; i < refs.length; i++) {
+ if (filters[i] != null) {
+ bundleContext.ungetService(refs[i]);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * A {@link FilterChain} composed of {@link Filter}s with the
+ */
+class Chain implements FilterChain {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Chain.class);
+
+ int current;
+ final Filter[] filters;
+
+ Chain(Filter[] filters) {
+ this.filters = filters;
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
+ if (current < filters.length && !response.isCommitted()) {
+ Filter filter = filters[current++];
+ LOG.info("doFilter() on {}", filter);
+ filter.doFilter(request, response, this);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/main/java/org/apache/cxf/dosgi/common/intent/DefaultIntentMapFactory.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/cxf/dosgi/common/intent/DefaultIntentMapFactory.java b/common/src/main/java/org/apache/cxf/dosgi/common/intent/DefaultIntentMapFactory.java
new file mode 100644
index 0000000..395fe46
--- /dev/null
+++ b/common/src/main/java/org/apache/cxf/dosgi/common/intent/DefaultIntentMapFactory.java
@@ -0,0 +1,52 @@
+/**
+ * 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.common.intent;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cxf.binding.soap.Soap11;
+import org.apache.cxf.binding.soap.Soap12;
+import org.apache.cxf.binding.soap.SoapBindingConfiguration;
+import org.apache.cxf.binding.soap.SoapVersion;
+import org.apache.cxf.feature.LoggingFeature;
+
+public class DefaultIntentMapFactory {
+
+ public Map<String, Object> create() {
+ Map<String, Object> intentMap = new HashMap<String, Object>();
+ intentMap.put("logging", getLoggingFeature());
+ Object soap11 = getSoapBinding(Soap11.getInstance());
+ intentMap.put("SOAP", soap11);
+ intentMap.put("SOAP.1_1", soap11);
+ intentMap.put("SOAP.1_2", getSoapBinding(Soap12.getInstance()));
+ intentMap.put("HTTP", "PROVIDED");
+ return intentMap;
+ }
+
+ private Object getLoggingFeature() {
+ return new LoggingFeature();
+ }
+
+ private Object getSoapBinding(SoapVersion soapVersion) {
+ SoapBindingConfiguration soapBindingConfig = new SoapBindingConfiguration();
+ soapBindingConfig.setVersion(soapVersion);
+ return soapBindingConfig;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentManager.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentManager.java b/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentManager.java
new file mode 100644
index 0000000..32eedab
--- /dev/null
+++ b/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentManager.java
@@ -0,0 +1,35 @@
+/**
+ * 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.common.intent;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.endpoint.AbstractEndpointFactory;
+import org.apache.cxf.feature.Feature;
+
+public interface IntentManager {
+ @Deprecated
+ String EXPORTED_INTENTS_OLD = "osgi.remote.requires.intents";
+
+ String INTENT_NAME_PROP = "org.apache.cxf.dosgi.IntentName";
+
+ String[] applyIntents(List<Feature> features, AbstractEndpointFactory factory, Map<String, Object> props);
+ void assertAllIntentsSupported(Map<String, Object> serviceProperties);
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentManagerImpl.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentManagerImpl.java b/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentManagerImpl.java
new file mode 100644
index 0000000..2775086
--- /dev/null
+++ b/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentManagerImpl.java
@@ -0,0 +1,214 @@
+/**
+ * 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.common.intent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.aries.rsa.spi.IntentUnsatisfiedException;
+import org.apache.cxf.binding.BindingConfiguration;
+import org.apache.cxf.dosgi.common.util.OsgiUtils;
+import org.apache.cxf.endpoint.AbstractEndpointFactory;
+import org.apache.cxf.feature.Feature;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(service = IntentManager.class)
+public class IntentManagerImpl implements IntentManager {
+
+ static final Logger LOG = LoggerFactory.getLogger(IntentManagerImpl.class);
+ private static final String PROVIDED_INTENT_VALUE = "PROVIDED";
+ private static final int DEFAULT_INTENT_TIMEOUT = 30000;
+
+ private final IntentMap intentMap;
+ private final long maxIntentWaitTime;
+ private IntentTracker tracker;
+
+ public IntentManagerImpl() {
+ this(DEFAULT_INTENT_TIMEOUT);
+ }
+
+ public IntentManagerImpl(int maxIntentWaitTime) {
+ this(new IntentMap(new DefaultIntentMapFactory().create()), maxIntentWaitTime);
+ }
+
+ public IntentManagerImpl(IntentMap intentMap) {
+ this(intentMap, DEFAULT_INTENT_TIMEOUT);
+ }
+
+ // For test
+ public IntentManagerImpl(IntentMap intentMap, int maxIntentWaitTime) {
+ this.maxIntentWaitTime = maxIntentWaitTime;
+ this.intentMap = intentMap;
+ }
+
+
+ @Activate
+ public void activate(BundleContext context) {
+ tracker = new IntentTracker(context, this.intentMap);
+ tracker.open();
+ }
+
+ @Deactivate
+ public void deactivate() {
+ tracker.close();
+ }
+
+ public String[] applyIntents(List<Feature> features, AbstractEndpointFactory factory,
+ Map<String, Object> props) throws IntentUnsatisfiedException {
+ Set<String> requestedIntents = IntentManagerImpl.getRequestedIntents(props);
+ Set<String> appliedIntents = new HashSet<String>();
+ appliedIntents.addAll(reverseLookup(intentMap, PROVIDED_INTENT_VALUE));
+ boolean bindingApplied = false;
+ for (String intentName : requestedIntents) {
+ bindingApplied |= processIntent(features, factory, intentName, intentMap.get(intentName));
+ appliedIntents.add(intentName);
+ }
+ if (!bindingApplied) {
+ String defaultBindingName = "SOAP";
+ processIntent(features, factory, defaultBindingName, intentMap.get(defaultBindingName));
+ appliedIntents.add(defaultBindingName);
+ }
+ appliedIntents.addAll(addSynonymIntents(appliedIntents, intentMap));
+ return appliedIntents.toArray(new String[appliedIntents.size()]);
+ }
+
+ private static Set<String> getRequestedIntents(Map<String, Object> sd) {
+ Collection<String> intents = OsgiUtils.getMultiValueProperty(sd.get(RemoteConstants.SERVICE_EXPORTED_INTENTS));
+ Collection<String> intents2
+ = OsgiUtils.getMultiValueProperty(sd.get(RemoteConstants.SERVICE_EXPORTED_INTENTS_EXTRA));
+ @SuppressWarnings("deprecation")
+ Collection<String> oldIntents = OsgiUtils.getMultiValueProperty(sd.get(IntentManager.EXPORTED_INTENTS_OLD));
+ Set<String> allIntents = new HashSet<String>();
+ if (intents != null) {
+ allIntents.addAll(parseIntents(intents));
+ }
+ if (intents2 != null) {
+ allIntents.addAll(parseIntents(intents2));
+ }
+ if (oldIntents != null) {
+ allIntents.addAll(parseIntents(oldIntents));
+ }
+
+ return allIntents;
+ }
+
+ private static Collection<String> parseIntents(Collection<String> intents) {
+ List<String> parsed = new ArrayList<String>();
+ for (String intent : intents) {
+ parsed.addAll(Arrays.asList(intent.split("[ ]")));
+ }
+ return parsed;
+ }
+
+ private boolean processIntent(List<Feature> features, AbstractEndpointFactory factory,
+ String intentName, Object intent) throws IntentUnsatisfiedException {
+ if (intent instanceof String) {
+ if (PROVIDED_INTENT_VALUE.equalsIgnoreCase((String) intent)) {
+ return false;
+ }
+ } else if (intent instanceof BindingConfiguration) {
+ BindingConfiguration bindingCfg = (BindingConfiguration)intent;
+ LOG.info("Applying intent: " + intentName + " via binding config: " + bindingCfg);
+ factory.setBindingConfig(bindingCfg);
+ return true;
+ } else if (intent instanceof Feature) {
+ Feature feature = (Feature) intent;
+ LOG.info("Applying intent: " + intentName + " via feature: " + feature);
+ features.add(feature);
+ return false;
+ } else {
+ LOG.info("No mapping for intent: " + intentName);
+ throw new IntentUnsatisfiedException(intentName);
+ }
+ return false;
+ }
+
+ private static Collection<String> addSynonymIntents(Collection<String> appliedIntents,
+ IntentMap map) {
+ // E.g. SOAP and SOAP.1_1 are synonyms
+ List<Object> values = new ArrayList<Object>();
+ for (String key : appliedIntents) {
+ values.add(map.get(key));
+ }
+ return reverseLookup(map, values);
+ }
+
+ private static Collection<String> reverseLookup(IntentMap im, Object obj) {
+ return reverseLookup(im, Collections.singleton(obj));
+ }
+
+ /**
+ * Retrieves all keys whose mapped values are found in the given collection.
+ *
+ * @param im an intent map
+ * @param values a collection of potential values
+ * @return all keys whose mapped values are found in the given collection
+ */
+ private static Collection<String> reverseLookup(IntentMap im, Collection<?> values) {
+ Set<String> intentsFound = new HashSet<String>();
+ for (Map.Entry<String, Object> entry : im.entrySet()) {
+ if (values.contains(entry.getValue())) {
+ intentsFound.add(entry.getKey());
+ }
+ }
+ return intentsFound;
+ }
+
+ public void assertAllIntentsSupported(Map<String, Object> serviceProperties) {
+ long endTime = System.currentTimeMillis() + maxIntentWaitTime;
+ Set<String> requiredIntents = IntentManagerImpl.getRequestedIntents(serviceProperties);
+ List<String> unsupportedIntents = new ArrayList<String>();
+ do {
+ unsupportedIntents.clear();
+ for (String ri : requiredIntents) {
+ if (!intentMap.containsKey(ri)) {
+ unsupportedIntents.add(ri);
+ }
+ }
+ long remainingSeconds = (endTime - System.currentTimeMillis()) / 1000;
+ if (!unsupportedIntents.isEmpty() && remainingSeconds > 0) {
+ LOG.debug("Waiting for custom intents " + unsupportedIntents + " timeout in " + remainingSeconds);
+ try {
+ synchronized (intentMap) {
+ intentMap.wait(1000);
+ }
+ } catch (InterruptedException e) {
+ LOG.warn(e.getMessage(), e);
+ }
+ }
+ } while (!unsupportedIntents.isEmpty() && System.currentTimeMillis() < endTime);
+
+ if (!unsupportedIntents.isEmpty()) {
+ throw new RuntimeException("service cannot be exported because the following "
+ + "intents are not supported by this RSA: " + unsupportedIntents);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentMap.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentMap.java b/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentMap.java
new file mode 100644
index 0000000..9539c95
--- /dev/null
+++ b/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentMap.java
@@ -0,0 +1,62 @@
+/**
+ * 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.common.intent;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Maps intent names to intent objects
+ * An intent object can be a Feature, a BindingConfiguration or a String
+ *
+ * Also supports a default intent map. Custom intents can override the defaults
+ */
+public class IntentMap extends ConcurrentHashMap<String, Object> {
+
+ private static final long serialVersionUID = 2606460607920520767L;
+ private Map<String, Object> defaultMap;
+
+ public IntentMap() {
+ this(new HashMap<String, Object>());
+ }
+
+ public IntentMap(Map<String, Object> defaultMap) {
+ this.defaultMap = defaultMap;
+ putAll(defaultMap);
+ }
+
+ @Override
+ public Object put(String key, Object value) {
+ Object result = super.put(key, value);
+ synchronized (this) {
+ notifyAll();
+ }
+ return result;
+ }
+
+ @Override
+ public Object remove(Object key) {
+ Object old = super.remove(key);
+ if (defaultMap.containsKey(key)) {
+ put((String)key, defaultMap.get(key));
+ }
+ return old;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentTracker.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentTracker.java b/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentTracker.java
new file mode 100644
index 0000000..678e9e5
--- /dev/null
+++ b/common/src/main/java/org/apache/cxf/dosgi/common/intent/IntentTracker.java
@@ -0,0 +1,61 @@
+/**
+ * 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.common.intent;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class IntentTracker extends ServiceTracker {
+
+ private final IntentMap intentMap;
+
+
+ public IntentTracker(BundleContext context, IntentMap intentMap) {
+ super(context, getFilter(context), null);
+ this.intentMap = intentMap;
+ }
+
+ static Filter getFilter(BundleContext context) {
+ try {
+ return context.createFilter("(" + IntentManager.INTENT_NAME_PROP + "=*)");
+ } catch (InvalidSyntaxException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public Object addingService(ServiceReference reference) {
+ String intentName = (String) reference.getProperty(IntentManager.INTENT_NAME_PROP);
+ Object intent = super.addingService(reference);
+ IntentManagerImpl.LOG.info("Adding custom intent " + intentName);
+ intentMap.put(intentName, intent);
+ return intent;
+ }
+
+ @Override
+ public void removedService(ServiceReference reference, Object service) {
+ String intentName = (String) reference.getProperty(IntentManager.INTENT_NAME_PROP);
+ intentMap.remove(intentName);
+ super.removedService(reference, service);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/main/java/org/apache/cxf/dosgi/common/util/ClassUtils.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/cxf/dosgi/common/util/ClassUtils.java b/common/src/main/java/org/apache/cxf/dosgi/common/util/ClassUtils.java
new file mode 100644
index 0000000..9190b6c
--- /dev/null
+++ b/common/src/main/java/org/apache/cxf/dosgi/common/util/ClassUtils.java
@@ -0,0 +1,86 @@
+/**
+ * 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.common.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.helpers.CastUtils;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class ClassUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassUtils.class);
+
+ private ClassUtils() {
+ }
+
+ public static List<Object> loadProviderClasses(BundleContext callingContext,
+ Map<String, Object> sd, String propName) {
+ Object serviceProviders = sd.get(propName);
+ if (serviceProviders != null) {
+ if (serviceProviders.getClass().isArray()) {
+ if (serviceProviders.getClass().getComponentType() == String.class) {
+ return loadProviders(callingContext, (String[])serviceProviders);
+ } else {
+ return Arrays.asList((Object[])serviceProviders);
+ }
+ } else if (serviceProviders.getClass() == String.class) {
+ String[] classNames = serviceProviders.toString().split(",");
+ return loadProviders(callingContext, classNames);
+ } else if (serviceProviders instanceof List) {
+ List<Object> list = CastUtils.cast((List<?>)serviceProviders);
+ if (!list.isEmpty()) {
+ List<Object> providers;
+ if (list.get(0).getClass() == String.class) {
+ providers = loadProviders(callingContext, list.toArray(new String[]{}));
+ } else {
+ providers = list;
+ }
+ return providers;
+ }
+ } else {
+ return Arrays.asList(serviceProviders);
+ }
+ }
+ return Collections.emptyList();
+
+ }
+
+ private static List<Object> loadProviders(BundleContext callingContext, String[] classNames) {
+ List<Object> providers = new ArrayList<Object>();
+ for (String className : classNames) {
+ try {
+ String realName = className.trim();
+ if (!realName.isEmpty()) {
+ Class<?> pClass = callingContext.getBundle().loadClass(realName);
+ providers.add(pClass.newInstance());
+ }
+ } catch (Exception ex) {
+ LOG.warn("Provider " + className.trim() + " can not be loaded or created " + ex.getMessage(), ex);
+ }
+ }
+ return providers;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/main/java/org/apache/cxf/dosgi/common/util/OsgiUtils.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/cxf/dosgi/common/util/OsgiUtils.java b/common/src/main/java/org/apache/cxf/dosgi/common/util/OsgiUtils.java
new file mode 100644
index 0000000..aa24903
--- /dev/null
+++ b/common/src/main/java/org/apache/cxf/dosgi/common/util/OsgiUtils.java
@@ -0,0 +1,78 @@
+/**
+ * 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.common.util;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class OsgiUtils {
+
+ public static final Logger LOG = LoggerFactory.getLogger(OsgiUtils.class);
+
+ private OsgiUtils() {
+ }
+
+ public static boolean getBooleanProperty(Map<String, Object> sd, String name) {
+ return toBoolean(sd.get(name));
+ }
+
+ public static boolean toBoolean(Object value) {
+ return value instanceof Boolean && (Boolean) value
+ || value instanceof String && Boolean.parseBoolean((String)value);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Collection<String> getMultiValueProperty(Object property) {
+ if (property == null) {
+ return null;
+ } else if (property instanceof Collection) {
+ return (Collection<String>)property;
+ } else if (property instanceof String[]) {
+ return Arrays.asList((String[])property);
+ } else {
+ return Collections.singleton(property.toString());
+ }
+ }
+
+ public static String getProperty(EndpointDescription endpoint, String name) {
+ return getProperty(endpoint.getProperties(), name);
+ }
+
+ public static String getProperty(Map<String, Object> dict, String name) {
+ Object value = dict.get(name);
+ return value instanceof String ? (String) value : null;
+ }
+
+ public static String getFirstNonEmptyStringProperty(Map<String, Object> dict, String ... keys) {
+ for (String key : keys) {
+ String value = getProperty(dict, key);
+ if (value != null) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/main/java/org/apache/cxf/dosgi/common/util/ServerWrapper.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/cxf/dosgi/common/util/ServerWrapper.java b/common/src/main/java/org/apache/cxf/dosgi/common/util/ServerWrapper.java
new file mode 100644
index 0000000..22144ca
--- /dev/null
+++ b/common/src/main/java/org/apache/cxf/dosgi/common/util/ServerWrapper.java
@@ -0,0 +1,49 @@
+/**
+ * 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.common.util;
+
+import java.io.IOException;
+
+import org.apache.aries.rsa.spi.Endpoint;
+import org.apache.cxf.endpoint.Server;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+
+public class ServerWrapper implements Endpoint {
+ private EndpointDescription desc;
+ private Server server;
+
+ public ServerWrapper(EndpointDescription desc, Server server) {
+ this.desc = desc;
+ this.server = server;
+ }
+
+ public Server getServer() {
+ return this.server;
+ }
+
+ @Override
+ public void close() throws IOException {
+ this.server.destroy();
+ }
+
+ @Override
+ public EndpointDescription description() {
+ return this.desc;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/main/java/org/apache/cxf/dosgi/common/util/StringPlus.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/cxf/dosgi/common/util/StringPlus.java b/common/src/main/java/org/apache/cxf/dosgi/common/util/StringPlus.java
new file mode 100644
index 0000000..c7123b2
--- /dev/null
+++ b/common/src/main/java/org/apache/cxf/dosgi/common/util/StringPlus.java
@@ -0,0 +1,72 @@
+/**
+ * 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.common.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class StringPlus {
+
+ private static final Logger LOG = LoggerFactory.getLogger(StringPlus.class);
+
+ private StringPlus() {
+ // never constructed
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static String[] normalize(Object object) {
+ if (object instanceof String) {
+ String s = (String)object;
+ String[] values = s.split(",");
+ List<String> list = new ArrayList<String>();
+ for (String val : values) {
+ String actualValue = val.trim();
+ if (!actualValue.isEmpty()) {
+ list.add(actualValue);
+ }
+ }
+ return list.toArray(new String[list.size()]);
+ }
+
+ if (object instanceof String[]) {
+ return (String[])object;
+ }
+
+ if (object instanceof Collection) {
+ Collection col = (Collection)object;
+ List<String> ar = new ArrayList<String>(col.size());
+ for (Object o : col) {
+ if (o instanceof String) {
+ String s = (String)o;
+ ar.add(s);
+ } else {
+ LOG.warn("stringPlus contained non string element in list! Element was skipped");
+ }
+ }
+ return ar.toArray(new String[ar.size()]);
+ }
+
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/test/java/org/apache/cxf/dosgi/common/httpservice/HttpServiceManagerTest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/cxf/dosgi/common/httpservice/HttpServiceManagerTest.java b/common/src/test/java/org/apache/cxf/dosgi/common/httpservice/HttpServiceManagerTest.java
new file mode 100644
index 0000000..c943f79
--- /dev/null
+++ b/common/src/test/java/org/apache/cxf/dosgi/common/httpservice/HttpServiceManagerTest.java
@@ -0,0 +1,118 @@
+/**
+ * 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.common.httpservice;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+
+import java.util.Dictionary;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+import org.junit.Assert;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+
+import junit.framework.TestCase;
+
+public class HttpServiceManagerTest extends TestCase {
+
+ public void testGetAbsoluteAddress() {
+ HttpServiceManager manager = new HttpServiceManager();
+ manager.initFromConfig(null);
+ String localIp = LocalHostUtil.getLocalIp();
+
+ String address1 = manager.getAbsoluteAddress(null, "/myservice");
+ assertEquals("http://" + localIp + ":8181/cxf/myservice", address1);
+
+ String address2 = manager.getAbsoluteAddress("/mycontext", "/myservice");
+ assertEquals("http://" + localIp + ":8181/mycontext/myservice", address2);
+ }
+
+ public void testRegisterAndUnregisterServlet() throws Exception {
+ IMocksControl c = EasyMock.createControl();
+ BundleContext dswContext = c.createMock(BundleContext.class);
+ Filter filter = c.createMock(Filter.class);
+ expect(dswContext.createFilter(EasyMock.eq("(service.id=12345)"))).andReturn(filter).once();
+ Capture<ServiceListener> captured = EasyMock.newCapture();
+ dswContext.addServiceListener(EasyMock.capture(captured), EasyMock.<String>anyObject());
+ expectLastCall().atLeastOnce();
+ expect(dswContext.getProperty("org.apache.cxf.httpservice.requirefilter")).andReturn(null).atLeastOnce();
+ ServletConfig config = c.createMock(ServletConfig.class);
+ expect(config.getInitParameter(EasyMock.<String>anyObject())).andReturn(null).atLeastOnce();
+ ServletContext servletContext = c.createMock(ServletContext.class);
+ expect(config.getServletContext()).andReturn(servletContext);
+ final HttpService httpService = new DummyHttpService(config);
+ ServiceReference<?> sr = c.createMock(ServiceReference.class);
+ expect(sr.getProperty(EasyMock.eq("service.id"))).andReturn(12345L).atLeastOnce();
+ expect(servletContext.getResourceAsStream((String)EasyMock.anyObject())).andReturn(null).anyTimes();
+ c.replay();
+
+ HttpServiceManager h = new HttpServiceManager();
+ h.setContext(dswContext);
+ h.setHttpService(httpService);
+ Bus bus = BusFactory.newInstance().createBus();
+ h.registerServlet(bus, "/myService", dswContext, 12345L);
+
+ ServiceEvent event = new ServiceEvent(ServiceEvent.UNREGISTERING, sr);
+ captured.getValue().serviceChanged(event);
+ c.verify();
+ }
+
+ static class DummyHttpService implements HttpService {
+
+ private ServletConfig config;
+
+ DummyHttpService(ServletConfig config) {
+ this.config = config;
+ }
+
+ @SuppressWarnings("rawtypes")
+ public void registerServlet(String alias, Servlet servlet, Dictionary initparams, HttpContext context)
+ throws ServletException, NamespaceException {
+ Assert.assertEquals("/myService", alias);
+ servlet.init(config);
+ }
+
+ public void registerResources(String alias, String name, HttpContext context) throws NamespaceException {
+ throw new RuntimeException("This method should not be called");
+ }
+
+ public void unregister(String alias) {
+ }
+
+ public HttpContext createDefaultHttpContext() {
+ return EasyMock.createNiceMock(HttpContext.class);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/test/java/org/apache/cxf/dosgi/common/httpservice/SecurityDelegatingHttpContextTest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/cxf/dosgi/common/httpservice/SecurityDelegatingHttpContextTest.java b/common/src/test/java/org/apache/cxf/dosgi/common/httpservice/SecurityDelegatingHttpContextTest.java
new file mode 100644
index 0000000..aac1204
--- /dev/null
+++ b/common/src/test/java/org/apache/cxf/dosgi/common/httpservice/SecurityDelegatingHttpContextTest.java
@@ -0,0 +1,267 @@
+/**
+ * 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.common.httpservice;
+
+import java.io.PrintWriter;
+import java.net.URL;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpContext;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings({
+ "unchecked", "rawtypes"
+ })
+public class SecurityDelegatingHttpContextTest extends TestCase {
+
+ protected HttpContext defaultHttpContext;
+ protected SecurityDelegatingHttpContext httpContext;
+ protected CommitResponseFilter commitFilter;
+ protected DoNothingFilter doNothingFilter;
+ protected AccessDeniedFilter accessDeniedFilter;
+ protected String mimeType;
+ protected URL url; // does not need to exist
+
+ public void setUp() throws Exception {
+ mimeType = "text/xml";
+ url = new URL("file:test.xml"); // does not need to exist
+
+ // Sample filters
+ commitFilter = new CommitResponseFilter();
+ doNothingFilter = new DoNothingFilter();
+ accessDeniedFilter = new AccessDeniedFilter();
+
+ // Mock up the default http context
+ defaultHttpContext = EasyMock.createNiceMock(HttpContext.class);
+ EasyMock.expect(defaultHttpContext.getMimeType((String)EasyMock.anyObject())).andReturn(mimeType);
+ EasyMock.expect(defaultHttpContext.getResource((String)EasyMock.anyObject())).andReturn(url);
+ EasyMock.replay(defaultHttpContext);
+ }
+
+ public void testFilterRequired() throws Exception {
+ // Mock up the service references
+ ServiceReference[] serviceReferences = new ServiceReference[] {};
+
+ // Mock up the bundle context
+ BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class);
+ EasyMock.expect(bundleContext.getServiceReferences(Filter.class.getName(),
+ "(org.apache.cxf.httpservice.filter=true)"))
+ .andReturn(serviceReferences);
+ EasyMock.replay(bundleContext);
+
+ // Set up the secure http context
+ httpContext = new SecurityDelegatingHttpContext(bundleContext, defaultHttpContext);
+ httpContext.requireFilter = true;
+
+ // Ensure that the httpContext doesn't allow the request to be processed, since there are no registered servlet
+ // filters
+ HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+ EasyMock.replay(request);
+ HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+ EasyMock.replay(response);
+ boolean requestAllowed = httpContext.handleSecurity(request, response);
+ Assert.assertFalse(requestAllowed);
+
+ // Ensure that the httpContext returns true if there is no requirement for registered servlet filters
+ httpContext.requireFilter = false;
+ requestAllowed = httpContext.handleSecurity(request, response);
+ Assert.assertTrue(requestAllowed);
+ }
+
+ public void testSingleCommitFilter() throws Exception {
+ // Mock up the service references
+ ServiceReference filterReference = EasyMock.createNiceMock(ServiceReference.class);
+ EasyMock.replay(filterReference);
+ ServiceReference[] serviceReferences = new ServiceReference[] {
+ filterReference
+ };
+
+ // Mock up the bundle context
+ BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class);
+ EasyMock.expect(bundleContext.getServiceReferences((String)EasyMock.anyObject(), (String)EasyMock.anyObject()))
+ .andReturn(serviceReferences);
+ EasyMock.expect(bundleContext.getService((ServiceReference)EasyMock.anyObject())).andReturn(commitFilter);
+ EasyMock.replay(bundleContext);
+
+ // Set up the secure http context
+ httpContext = new SecurityDelegatingHttpContext(bundleContext, defaultHttpContext);
+
+ // Ensure that the httpContext returns false, since the filter has committed the response
+ HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+ EasyMock.replay(request);
+ HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+ EasyMock.expect(response.isCommitted()).andReturn(false); // the first call checks to see whether to invoke the
+ // filter
+ EasyMock.expect(response.isCommitted()).andReturn(true); // the second is called to determine the handleSecurity
+ // return value
+ EasyMock.expect(response.getWriter()).andReturn(new PrintWriter(System.out));
+ EasyMock.replay(response);
+ Assert.assertFalse(httpContext.handleSecurity(request, response));
+
+ // Ensure that the appropriate filters were called
+ Assert.assertTrue(commitFilter.called);
+ Assert.assertFalse(doNothingFilter.called);
+ Assert.assertFalse(accessDeniedFilter.called);
+ }
+
+ public void testFilterChain() throws Exception {
+ // Mock up the service references
+ ServiceReference filterReference = EasyMock.createNiceMock(ServiceReference.class);
+ EasyMock.replay(filterReference);
+ ServiceReference[] serviceReferences = new ServiceReference[] {
+ filterReference, filterReference
+ };
+
+ // Mock up the bundle context
+ BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class);
+ EasyMock.expect(bundleContext.getServiceReferences((String)EasyMock.anyObject(), (String)EasyMock.anyObject()))
+ .andReturn(serviceReferences);
+ EasyMock.expect(bundleContext.getService((ServiceReference)EasyMock.anyObject())).andReturn(doNothingFilter);
+ EasyMock.expect(bundleContext.getService((ServiceReference)EasyMock.anyObject())).andReturn(commitFilter);
+ EasyMock.replay(bundleContext);
+
+ // Set up the secure http context
+ httpContext = new SecurityDelegatingHttpContext(bundleContext, defaultHttpContext);
+
+ // Ensure that the httpContext returns false, since the filter has committed the response
+ HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+ EasyMock.replay(request);
+ HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+ EasyMock.expect(response.isCommitted()).andReturn(false); // doNothingFilter should not commit the response
+ EasyMock.expect(response.getWriter()).andReturn(new PrintWriter(System.out));
+ EasyMock.expect(response.isCommitted()).andReturn(false);
+ EasyMock.expect(response.isCommitted()).andReturn(true); // the commit filter indicating that it committed the
+ // response
+ EasyMock.replay(response);
+ Assert.assertFalse(httpContext.handleSecurity(request, response));
+
+ // Ensure that the appropriate filters were called
+ Assert.assertTrue(doNothingFilter.called);
+ Assert.assertTrue(commitFilter.called);
+ Assert.assertFalse(accessDeniedFilter.called);
+ }
+
+ public void testAllowRequest() throws Exception {
+ // Mock up the service references
+ ServiceReference filterReference = EasyMock.createNiceMock(ServiceReference.class);
+ EasyMock.replay(filterReference);
+ ServiceReference[] serviceReferences = new ServiceReference[] {
+ filterReference
+ };
+
+ // Mock up the bundle context
+ BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class);
+ EasyMock.expect(bundleContext.getServiceReferences((String)EasyMock.anyObject(), (String)EasyMock.anyObject()))
+ .andReturn(serviceReferences);
+ EasyMock.expect(bundleContext.getService((ServiceReference)EasyMock.anyObject())).andReturn(doNothingFilter);
+ EasyMock.replay(bundleContext);
+
+ // Set up the secure http context
+ httpContext = new SecurityDelegatingHttpContext(bundleContext, defaultHttpContext);
+
+ // Ensure that the httpContext returns true, since the filter has not committed the response
+ HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+ EasyMock.replay(request);
+ HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+ EasyMock.expect(response.isCommitted()).andReturn(false);
+ EasyMock.replay(response);
+ Assert.assertTrue(httpContext.handleSecurity(request, response));
+
+ // Ensure that the appropriate filters were called
+ Assert.assertTrue(doNothingFilter.called);
+ Assert.assertFalse(commitFilter.called);
+ Assert.assertFalse(accessDeniedFilter.called);
+ }
+
+ public void testDelegation() throws Exception {
+ BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class);
+ EasyMock.replay(bundleContext);
+
+ // Set up the secure http context
+ httpContext = new SecurityDelegatingHttpContext(bundleContext, defaultHttpContext);
+
+ // Ensure that it delegates non-security calls to the wrapped implementation (in this case, the mock)
+ Assert.assertEquals(mimeType, httpContext.getMimeType(""));
+ Assert.assertEquals(url, httpContext.getResource(""));
+ }
+}
+
+class CommitResponseFilter implements Filter {
+
+ boolean called;
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ public void destroy() {
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws java.io.IOException, javax.servlet.ServletException {
+ called = true;
+ response.getWriter().write("committing the response");
+ }
+}
+
+class DoNothingFilter implements Filter {
+
+ boolean called;
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ public void destroy() {
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws java.io.IOException, javax.servlet.ServletException {
+ called = true;
+ chain.doFilter(request, response);
+ }
+}
+
+class AccessDeniedFilter implements Filter {
+
+ boolean called;
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ public void destroy() {
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws java.io.IOException, javax.servlet.ServletException {
+ called = true;
+ ((HttpServletResponse)response).sendError(HttpServletResponse.SC_FORBIDDEN);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/d2a3c75f/common/src/test/java/org/apache/cxf/dosgi/common/qos/IntentManagerImplTest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/cxf/dosgi/common/qos/IntentManagerImplTest.java b/common/src/test/java/org/apache/cxf/dosgi/common/qos/IntentManagerImplTest.java
new file mode 100644
index 0000000..63a2fef
--- /dev/null
+++ b/common/src/test/java/org/apache/cxf/dosgi/common/qos/IntentManagerImplTest.java
@@ -0,0 +1,282 @@
+/**
+ * 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.common.qos;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.aries.rsa.spi.IntentUnsatisfiedException;
+import org.apache.cxf.binding.BindingConfiguration;
+import org.apache.cxf.dosgi.common.intent.DefaultIntentMapFactory;
+import org.apache.cxf.dosgi.common.intent.IntentManager;
+import org.apache.cxf.dosgi.common.intent.IntentManagerImpl;
+import org.apache.cxf.dosgi.common.intent.IntentMap;
+import org.apache.cxf.endpoint.AbstractEndpointFactory;
+import org.apache.cxf.feature.AbstractFeature;
+import org.apache.cxf.feature.Feature;
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class IntentManagerImplTest extends Assert {
+
+ @Test
+ public void testIntents() throws Exception {
+ Map<String, Object> intents = new HashMap<String, Object>();
+ intents.put("A", new TestFeature("A"));
+ intents.put("SOAP", new TestFeature("SOAP"));
+ final IntentMap intentMap = new IntentMap(intents);
+
+ IMocksControl control = EasyMock.createNiceControl();
+ List<Feature> features = new ArrayList<Feature>();
+ AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+ control.replay();
+
+ IntentManager intentManager = new IntentManagerImpl(intentMap, 10000);
+
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("osgi.remote.requires.intents", "A");
+
+ List<String> effectiveIntents = Arrays.asList(intentManager.applyIntents(features, factory, props));
+ assertEquals(Arrays.asList("A", "SOAP"), effectiveIntents);
+ }
+
+ @Test
+ public void testMultiIntents() {
+ final IntentMap intentMap = new IntentMap(new DefaultIntentMapFactory().create());
+ intentMap.put("confidentiality.message", new TestFeature("confidentiality.message"));
+ intentMap.put("transactionality", new TestFeature("transactionality"));
+
+ IMocksControl control = EasyMock.createNiceControl();
+ List<Feature> features = new ArrayList<Feature>();
+ AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+ control.replay();
+
+ IntentManager intentManager = new IntentManagerImpl(intentMap);
+
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("osgi.remote.requires.intents", "transactionality confidentiality.message");
+
+ List<String> effectiveIntents = Arrays.asList(intentManager.applyIntents(features, factory, props));
+ assertTrue(effectiveIntents.contains("transactionality"));
+ assertTrue(effectiveIntents.contains("confidentiality.message"));
+ }
+
+ @Test
+ public void testFailedIntent() {
+ Map<String, Object> intents = new HashMap<String, Object>();
+ intents.put("A", new TestFeature("A"));
+ final IntentMap intentMap = new IntentMap(intents);
+
+ IMocksControl control = EasyMock.createNiceControl();
+ List<Feature> features = new ArrayList<Feature>();
+ AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+ control.replay();
+
+ IntentManager intentManager = new IntentManagerImpl(intentMap);
+
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("osgi.remote.requires.intents", "A B");
+ // ServiceEndpointDescription sd =
+ // new ServiceEndpointDescriptionImpl(Arrays.asList(String.class.getName()), props);
+
+ try {
+ intentManager.applyIntents(features, factory, props);
+ Assert.fail("applyIntents() should have thrown an exception as there was an unsatisfiable intent");
+ } catch (IntentUnsatisfiedException iue) {
+ assertEquals("B", iue.getIntent());
+ }
+ }
+
+ @Test
+ public void testInferIntents() {
+ Map<String, Object> intents = new HashMap<String, Object>();
+ intents.put("SOAP", new TestFeature("SOAP"));
+ intents.put("Prov", "PROVIDED");
+ AbstractFeature feat1 = new TestFeature("feat1");
+ intents.put("A", feat1);
+ intents.put("A_alt", feat1);
+ intents.put("B", new TestFeature("B"));
+ final IntentMap intentMap = new IntentMap(intents);
+
+ IMocksControl control = EasyMock.createNiceControl();
+ List<Feature> features = new ArrayList<Feature>();
+ AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+ control.replay();
+
+ IntentManager intentManager = new IntentManagerImpl(intentMap);
+
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("osgi.remote.requires.intents", "A");
+ // ServiceEndpointDescription sd =
+ // new ServiceEndpointDescriptionImpl(Arrays.asList(String.class.getName()), props);
+
+ List<String> effectiveIntents = Arrays.asList(intentManager.applyIntents(features, factory, props));
+ assertEquals(4, effectiveIntents.size());
+ assertTrue(effectiveIntents.contains("Prov"));
+ assertTrue(effectiveIntents.contains("A"));
+ assertTrue(effectiveIntents.contains("A_alt"));
+ }
+
+ @Test
+ public void testDefaultBindingIntent() {
+ IMocksControl control = EasyMock.createNiceControl();
+
+ Map<String, Object> intents = new HashMap<String, Object>();
+ BindingConfiguration feat1 = control.createMock(BindingConfiguration.class);
+ intents.put("A", new AbstractFeature() {
+ });
+ intents.put("SOAP", feat1);
+ intents.put("SOAP.1_1", feat1);
+ intents.put("SOAP.1_2", control.createMock(BindingConfiguration.class));
+ final IntentMap intentMap = new IntentMap(intents);
+
+ List<Feature> features = new ArrayList<Feature>();
+ AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+ control.replay();
+ IntentManager intentManager = new IntentManagerImpl(intentMap);
+
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("osgi.remote.requires.intents", "A");
+ // ServiceEndpointDescription sd =
+ // new ServiceEndpointDescriptionImpl(Arrays.asList(String.class.getName()), props);
+
+ List<String> effectiveIntents = Arrays.asList(intentManager.applyIntents(features, factory, props));
+ assertEquals(3, effectiveIntents.size());
+ assertTrue(effectiveIntents.contains("A"));
+ assertTrue(effectiveIntents.contains("SOAP"));
+ assertTrue(effectiveIntents.contains("SOAP.1_1"));
+ }
+
+ @Test
+ public void testExplicitBindingIntent() {
+ IMocksControl control = EasyMock.createNiceControl();
+
+ Map<String, Object> intents = new HashMap<String, Object>();
+ BindingConfiguration feat1 = control.createMock(BindingConfiguration.class);
+ intents.put("A", new AbstractFeature() {
+ });
+ intents.put("SOAP", feat1);
+ intents.put("SOAP.1_1", feat1);
+ intents.put("SOAP.1_2", control.createMock(BindingConfiguration.class));
+ final IntentMap intentMap = new IntentMap(intents);
+
+ List<Feature> features = new ArrayList<Feature>();
+ AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+ control.replay();
+
+ IntentManager intentManager = new IntentManagerImpl(intentMap);
+
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("osgi.remote.requires.intents", "A SOAP.1_2");
+ // ServiceEndpointDescription sd =
+ // new ServiceEndpointDescriptionImpl(Arrays.asList(String.class.getName()), props);
+
+ List<String> effectiveIntents = Arrays.asList(intentManager.applyIntents(features, factory, props));
+ assertEquals(2, effectiveIntents.size());
+ assertTrue(effectiveIntents.contains("A"));
+ assertTrue(effectiveIntents.contains("SOAP.1_2"));
+ }
+
+ public void testInheritMasterIntentMapDefault() {
+ List<String> features = runTestInheritMasterIntentMap("A B");
+
+ assertEquals(2, features.size());
+ assertTrue(features.contains("appFeatureA"));
+ assertTrue(features.contains("masterFeatureB"));
+ }
+
+ public void testInheritMasterIntentMap() {
+ List<String> features = runTestInheritMasterIntentMap("A B");
+
+ assertEquals(2, features.size());
+ assertTrue(features.contains("appFeatureA"));
+ assertTrue(features.contains("masterFeatureB"));
+ }
+
+ private List<String> runTestInheritMasterIntentMap(String requestedIntents) {
+ Map<String, Object> masterIntents = new HashMap<String, Object>();
+ masterIntents.put("A", new TestFeature("masterFeatureA"));
+ masterIntents.put("B", new TestFeature("masterFeatureB"));
+ final IntentMap intentMap = new IntentMap(masterIntents);
+ intentMap.put("A", new TestFeature("appFeatureA"));
+
+ IMocksControl control = EasyMock.createNiceControl();
+ List<Feature> features = new ArrayList<Feature>();
+ AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+ control.replay();
+
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("osgi.remote.requires.intents", requestedIntents);
+
+ IntentManagerImpl intentManager = new IntentManagerImpl(intentMap);
+ intentManager.applyIntents(features, factory, props);
+
+ List<String> featureNames = new ArrayList<String>();
+ for (Feature f : features) {
+ featureNames.add(f.toString());
+ }
+ return featureNames;
+ }
+
+ @Test
+ public void testProvidedIntents() {
+ Map<String, Object> masterIntents = new HashMap<String, Object>();
+ masterIntents.put("SOAP", "SOAP");
+ masterIntents.put("A", "Provided");
+ masterIntents.put("B", "PROVIDED");
+ final IntentMap intentMap = new IntentMap(masterIntents);
+
+ IMocksControl control = EasyMock.createNiceControl();
+ List<Feature> features = new ArrayList<Feature>();
+ AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+ control.replay();
+
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("osgi.remote.requires.intents", "B A");
+
+ IntentManager intentManager = new IntentManagerImpl(intentMap);
+
+ Set<String> effectiveIntents = new HashSet<String>(Arrays.asList(intentManager.applyIntents(features,
+ factory,
+ props)));
+ Set<String> expectedIntents = new HashSet<String>(Arrays.asList(new String[] {"A", "B", "SOAP"}));
+ assertEquals(expectedIntents, effectiveIntents);
+ }
+
+ private static final class TestFeature extends AbstractFeature {
+
+ private final String name;
+
+ private TestFeature(String n) {
+ name = n;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+}