You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by km...@apache.org on 2013/11/27 16:12:40 UTC

git commit: KNOX-33: Provide support for hosting Jersey services

Updated Branches:
  refs/heads/master 9901058dc -> 6a4101a0e


KNOX-33: Provide support for hosting Jersey services


Project: http://git-wip-us.apache.org/repos/asf/incubator-knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-knox/commit/6a4101a0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-knox/tree/6a4101a0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-knox/diff/6a4101a0

Branch: refs/heads/master
Commit: 6a4101a0e08faf38af51c6812b9d84981221021a
Parents: 9901058
Author: Kevin Minder <ke...@hortonworks.com>
Authored: Wed Nov 27 10:05:26 2013 -0500
Committer: Kevin Minder <ke...@hortonworks.com>
Committed: Wed Nov 27 10:12:22 2013 -0500

----------------------------------------------------------------------
 gateway-provider-jersey/pom.xml                 |  83 ++++++
 .../JerseyDispatchDeploymentContributor.java    |  55 ++++
 .../JerseyServiceDeploymentContributorBase.java |  57 ++++
 ...gateway.deploy.ProviderDeploymentContributor |  19 ++
 .../jersey/JerseyDeploymentContributorTest.java | 259 +++++++++++++++++++
 .../filter/rewrite/impl/UrlRewriteRequest.java  |   2 +
 gateway-server/pom.xml                          |   9 +-
 gateway-test/pom.xml                            |  14 +-
 .../gateway/GatewayLocalServiceFuncTest.java    | 208 +++++++++++++++
 .../hadoop/gateway/TestJerseyService.java       |  34 +++
 .../TestJerseyServiceDeploymentContributor.java |  44 ++++
 ....gateway.deploy.ServiceDeploymentContributor |   1 +
 .../GatewayLocalServiceFuncTest/users.ldif      |  36 +++
 pom.xml                                         |  22 +-
 14 files changed, 831 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-provider-jersey/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-provider-jersey/pom.xml b/gateway-provider-jersey/pom.xml
new file mode 100644
index 0000000..b679b61
--- /dev/null
+++ b/gateway-provider-jersey/pom.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>gateway</artifactId>
+        <groupId>org.apache.hadoop</groupId>
+        <version>0.4.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>gateway-provider-jersey</artifactId>
+    <name>gateway-provider-jersey</name>
+    <description>An extension to the gateway that can internally dispatch to Jersey REST implementations.</description>
+
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+
+    <dependencies>
+
+        <dependency>
+          <groupId>org.glassfish.jersey.containers</groupId>
+          <artifactId>jersey-container-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-server</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-spi</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-server</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-test-utils</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>test-jetty-servlet</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-library</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-provider-jersey/src/main/java/org/apache/hadoop/gateway/jersey/JerseyDispatchDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-jersey/src/main/java/org/apache/hadoop/gateway/jersey/JerseyDispatchDeploymentContributor.java b/gateway-provider-jersey/src/main/java/org/apache/hadoop/gateway/jersey/JerseyDispatchDeploymentContributor.java
new file mode 100644
index 0000000..1f40fd7
--- /dev/null
+++ b/gateway-provider-jersey/src/main/java/org/apache/hadoop/gateway/jersey/JerseyDispatchDeploymentContributor.java
@@ -0,0 +1,55 @@
+/**
+ * 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.hadoop.gateway.jersey;
+
+import org.apache.hadoop.gateway.deploy.DeploymentContext;
+import org.apache.hadoop.gateway.deploy.ProviderDeploymentContributorBase;
+import org.apache.hadoop.gateway.descriptor.FilterDescriptor;
+import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
+import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
+import org.apache.hadoop.gateway.topology.Provider;
+import org.apache.hadoop.gateway.topology.Service;
+import org.glassfish.jersey.servlet.ServletContainer;
+
+import java.util.List;
+
+public class JerseyDispatchDeploymentContributor extends ProviderDeploymentContributorBase {
+
+  private static final String FILTER_CLASS_NAME = ServletContainer.class.getName();
+
+  @Override
+  public String getRole() {
+    return "pivot";
+  }
+
+  @Override
+  public String getName() {
+    return "jersey";
+  }
+
+  @Override
+  public void contributeFilter( DeploymentContext context, Provider provider, Service service, ResourceDescriptor resource, List<FilterParamDescriptor> params ) {
+    FilterDescriptor filter = resource.addFilter().name( getName() ).role( getRole() ).impl( FILTER_CLASS_NAME );
+    if( params != null ) {
+      for( FilterParamDescriptor param : params ) {
+        filter.param().name( param.name() ).value( param.value() );
+      }
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-provider-jersey/src/main/java/org/apache/hadoop/gateway/jersey/JerseyServiceDeploymentContributorBase.java
----------------------------------------------------------------------
diff --git a/gateway-provider-jersey/src/main/java/org/apache/hadoop/gateway/jersey/JerseyServiceDeploymentContributorBase.java b/gateway-provider-jersey/src/main/java/org/apache/hadoop/gateway/jersey/JerseyServiceDeploymentContributorBase.java
new file mode 100644
index 0000000..fc7f114
--- /dev/null
+++ b/gateway-provider-jersey/src/main/java/org/apache/hadoop/gateway/jersey/JerseyServiceDeploymentContributorBase.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.hadoop.gateway.jersey;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.gateway.deploy.DeploymentContext;
+import org.apache.hadoop.gateway.deploy.ServiceDeploymentContributorBase;
+import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
+import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
+import org.apache.hadoop.gateway.topology.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class JerseyServiceDeploymentContributorBase extends ServiceDeploymentContributorBase {
+
+  private static final String PACKAGES_PARAM = "jersey.config.server.provider.packages";
+
+  protected abstract String[] getPackages();
+
+  protected abstract String[] getPatterns();
+
+  public void contributeService( DeploymentContext context, Service service ) throws Exception {
+    String packages = StringUtils.join( getPackages(), ";" );
+    for( String pattern : getPatterns() ) {
+      ResourceDescriptor resource = context.getGatewayDescriptor().addResource();
+      resource.role( service.getRole() );
+      resource.pattern( pattern );
+      addAuthenticationFilter( context, service, resource );
+      addIdentityAssertionFilter( context, service, resource );
+      addAuthorizationFilter( context, service, resource );
+      // addRewriteFilter( context, service, resource, null );
+      List<FilterParamDescriptor> params = new ArrayList<FilterParamDescriptor>();
+      FilterParamDescriptor param = resource.createFilterParam();
+      param.name( PACKAGES_PARAM );
+      param.value( packages );
+      params.add( param );
+      context.contributeFilter( service, resource, "pivot", "jersey", params );
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-provider-jersey/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor
----------------------------------------------------------------------
diff --git a/gateway-provider-jersey/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor b/gateway-provider-jersey/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor
new file mode 100644
index 0000000..70af7b4
--- /dev/null
+++ b/gateway-provider-jersey/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor
@@ -0,0 +1,19 @@
+##########################################################################
+# 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.
+##########################################################################
+
+org.apache.hadoop.gateway.jersey.JerseyDispatchDeploymentContributor
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-provider-jersey/src/test/java/org/apache/hadoop/gateway/jersey/JerseyDeploymentContributorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-jersey/src/test/java/org/apache/hadoop/gateway/jersey/JerseyDeploymentContributorTest.java b/gateway-provider-jersey/src/test/java/org/apache/hadoop/gateway/jersey/JerseyDeploymentContributorTest.java
new file mode 100644
index 0000000..914ffa4
--- /dev/null
+++ b/gateway-provider-jersey/src/test/java/org/apache/hadoop/gateway/jersey/JerseyDeploymentContributorTest.java
@@ -0,0 +1,259 @@
+/**
+ * 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.hadoop.gateway.jersey;
+
+import org.apache.hadoop.gateway.config.GatewayConfig;
+import org.apache.hadoop.gateway.deploy.DeploymentContext;
+import org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor;
+import org.apache.hadoop.gateway.descriptor.FilterDescriptor;
+import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
+import org.apache.hadoop.gateway.descriptor.GatewayDescriptor;
+import org.apache.hadoop.gateway.descriptor.GatewayDescriptorFactory;
+import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
+import org.apache.hadoop.gateway.topology.Provider;
+import org.apache.hadoop.gateway.topology.Service;
+import org.apache.hadoop.gateway.topology.Topology;
+import org.easymock.EasyMock;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.jboss.shrinkwrap.descriptor.api.webapp30.WebAppDescriptor;
+import org.junit.Test;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.ServiceLoader;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.fail;
+
+public class JerseyDeploymentContributorTest {
+
+  @Test
+  public void testServiceLoader() throws Exception {
+    ServiceLoader loader = ServiceLoader.load( ProviderDeploymentContributor.class );
+    Iterator iterator = loader.iterator();
+    assertThat( "Service iterator empty.", iterator.hasNext() );
+    while( iterator.hasNext() ) {
+      Object object = iterator.next();
+      if( object instanceof JerseyDispatchDeploymentContributor ) {
+        return;
+      }
+    }
+    fail( "Failed to find " + JerseyDispatchDeploymentContributor.class.getName() + " via service loader." );
+  }
+
+  @Test
+  public void testDeploymentContributors() throws Exception {
+    JerseyDispatchDeploymentContributor providerContributor = new JerseyDispatchDeploymentContributor();
+    assertThat( providerContributor.getRole(), is( "pivot" ) );
+    assertThat( providerContributor.getName(), is( "jersey" ) );
+
+    MockJerseyService serviceContributor = new MockJerseyService();
+
+    WebArchive webArchive = ShrinkWrap.create( WebArchive.class, "test-archive" );
+
+    Topology topology = new Topology();
+    topology.setName( "test-topology" );
+    Provider provider = new Provider();
+    provider.setRole( "pivot" );
+    provider.setName( "jersey" );
+    provider.setEnabled( true );
+    topology.addProvider( provider );
+
+    GatewayDescriptor descriptor = GatewayDescriptorFactory.create();
+
+    DeploymentContext context = EasyMock.createNiceMock( DeploymentContext.class );
+    EasyMock.expect( context.getWebArchive() ).andReturn( webArchive ).anyTimes();
+    EasyMock.expect( context.getTopology() ).andReturn( topology ).anyTimes();
+    EasyMock.expect( context.getGatewayDescriptor() ).andReturn( descriptor ).anyTimes();
+    context.contributeFilter(
+        EasyMock.<Service> isA( Service.class ),
+        EasyMock.<ResourceDescriptor> isA( ResourceDescriptor.class ),
+        EasyMock.<String> isA( String.class ),
+        EasyMock.<String> isA( String.class ),
+        EasyMock.<List> isA( List.class ) );
+    EasyMock.expectLastCall().andDelegateTo(
+        new MockDeploymentContext( context, providerContributor, provider ) ).anyTimes();
+
+    EasyMock.replay( context );
+
+    // Just make sure they don't blow up.
+    providerContributor.initializeContribution( context );
+    serviceContributor.initializeContribution( context );
+
+    Service service = new Service();
+    service.setRole( "test-service-role" );
+    service.setName( "test-service-name" );
+    service.setUrl( "http://test-service-host:777/test-service-path" );
+
+    // This should end up calling providerContributor.contributeFilter
+    serviceContributor.contributeService( context, service );
+    ResourceDescriptor resource = context.getGatewayDescriptor().resources().get( 0 );
+
+    // Just make sure they don't blow up.
+    serviceContributor.finalizeContribution( context );
+    providerContributor.finalizeContribution( context );
+
+    /*
+    GatewayDescriptorFactory.store( descriptor, "xml", new PrintWriter( System.out ) );
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+    <gateway>
+      <resource>
+        <role>test-service-role</role>
+        <pattern>test-service/?**</pattern>
+        <filter>
+          <role>dispatch</role>
+          <name>jersey</name>
+          <class>org.glassfish.jersey.servlet.ServletContainer</class>
+          <param>
+            <name>jersey.config.server.provider.packages</name>
+            <value>test-package-1;test-package-2</value>
+          </param>
+        </filter>
+      </resource>
+      <resource>
+        <role>test-service-role</role>
+        <pattern>test-service/**?**</pattern>
+        <filter>
+          <role>dispatch</role>
+          <name>jersey</name>
+          <class>org.glassfish.jersey.servlet.ServletContainer</class>
+          <param>
+            <name>jersey.config.server.provider.packages</name>
+            <value>test-package-1;test-package-2</value>
+          </param>
+        </filter>
+      </resource>
+    </gateway>
+    */
+    List<ResourceDescriptor> resources = context.getGatewayDescriptor().resources();
+    assertThat( resources.size(), is( 2 ) );
+
+    resource = resources.get( 0 );
+    assertThat( resource.role(), is( "test-service-role" ) );
+    assertThat( resource.pattern(), is( "test-service/?**" ) );
+    List<FilterDescriptor> filters = resource.filters();
+    assertThat( filters.size(), is( 1 ) );
+    FilterDescriptor filter = filters.get( 0 );
+    assertThat( filter.role(), is( "pivot") );
+    assertThat( filter.name(), is( "jersey" ) );
+    assertThat( filter.impl(), is( "org.glassfish.jersey.servlet.ServletContainer" ) );
+    List<FilterParamDescriptor> params = filter.params();
+    assertThat( params.size(), is( 1 ) );
+    FilterParamDescriptor param = params.get( 0 );
+    assertThat( param.name(), is( "jersey.config.server.provider.packages" ) );
+    assertThat( param.value(), is( "test-package-1;test-package-2"  ) );
+
+    resource = resources.get( 1 );
+    assertThat( resource.role(), is( "test-service-role" ) );
+    assertThat( resource.pattern(), is( "test-service/**?**" ) );
+    filters = resource.filters();
+    assertThat( filters.size(), is( 1 ) );
+    filter = filters.get( 0 );
+    assertThat( filter.role(), is( "pivot") );
+    assertThat( filter.name(), is( "jersey" ) );
+    assertThat( filter.impl(), is( "org.glassfish.jersey.servlet.ServletContainer" ) );
+    params = filter.params();
+    assertThat( params.size(), is( 1 ) );
+    param = params.get( 0 );
+    assertThat( param.name(), is( "jersey.config.server.provider.packages" ) );
+    assertThat( param.value(), is( "test-package-1;test-package-2"  ) );
+  }
+
+  private static class MockJerseyService extends JerseyServiceDeploymentContributorBase {
+
+    @Override
+    protected String[] getPatterns() {
+      return new String[]{ "test-service/?**", "test-service/**?**" };
+    }
+
+    @Override
+    protected String[] getPackages() {
+      return new String[]{ "test-package-1", "test-package-2" };
+    }
+
+    @Override
+    public String getRole() {
+      return "test-service-role";
+    }
+
+    @Override
+    public String getName() {
+      return "test-service-name";
+    }
+
+  }
+
+  private static class MockDeploymentContext implements DeploymentContext {
+
+    DeploymentContext context;
+    ProviderDeploymentContributor providerContributor;
+    Provider provider;
+
+    public MockDeploymentContext(
+        DeploymentContext context,
+        ProviderDeploymentContributor providerContributor,
+        Provider provider ) {
+      this.context = context;
+      this.providerContributor = providerContributor;
+      this.provider = provider;
+    }
+
+    @Override
+    public GatewayConfig getGatewayConfig() {
+      return null;
+    }
+
+    @Override
+    public Topology getTopology() {
+      return null;
+    }
+
+    @Override
+    public WebArchive getWebArchive() {
+      return null;
+    }
+
+    @Override
+    public WebAppDescriptor getWebAppDescriptor() {
+      return null;
+    }
+
+    @Override
+    public GatewayDescriptor getGatewayDescriptor() {
+      return null;
+    }
+
+    @Override
+    public void contributeFilter( Service service, ResourceDescriptor resource, String role, String name, List<FilterParamDescriptor> params ) {
+      providerContributor.contributeFilter( context, provider, service, resource, params );
+    }
+
+    @Override
+    public void addDescriptor( String name, Object descriptor ) {
+    }
+
+    @Override
+    public <T> T getDescriptor( String name ) {
+      return null;
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteRequest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteRequest.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteRequest.java
index a12fc24..3a33ead 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteRequest.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteRequest.java
@@ -121,6 +121,8 @@ public class UrlRewriteRequest extends GatewayRequestWrapper implements Resolver
     return new StringBuffer( getRequestURI() );
   }
 
+  //TODO: I think this method is implemented wrong based on the HttpServletRequest.getRequestURI docs.
+  // It should not include the scheme or authority parts.
   @Override
   public String getRequestURI() {
     String[] split = splitTargetUrl( getTargetUrl() );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-server/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-server/pom.xml b/gateway-server/pom.xml
index 0bea177..35898c1 100644
--- a/gateway-server/pom.xml
+++ b/gateway-server/pom.xml
@@ -247,14 +247,13 @@
         </dependency>
 
         <dependency>
-            <groupId>com.sun.jersey</groupId>
-            <artifactId>jersey-server</artifactId>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-servlet</artifactId>
             <scope>test</scope>
         </dependency>
-
         <dependency>
-            <groupId>com.sun.jersey</groupId>
-            <artifactId>jersey-servlet</artifactId>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-server</artifactId>
             <scope>test</scope>
         </dependency>
 

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-test/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-test/pom.xml b/gateway-test/pom.xml
index ea044fb..f58ae40 100644
--- a/gateway-test/pom.xml
+++ b/gateway-test/pom.xml
@@ -35,6 +35,11 @@
             <artifactId>gateway-release</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-provider-jersey</artifactId>
+            <scope>test</scope>
+        </dependency>
 
         <dependency>
             <groupId>${gateway-group}</groupId>
@@ -127,14 +132,13 @@
         </dependency>
 
         <dependency>
-            <groupId>com.sun.jersey</groupId>
-            <artifactId>jersey-server</artifactId>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-servlet</artifactId>
             <scope>test</scope>
         </dependency>
-
         <dependency>
-            <groupId>com.sun.jersey</groupId>
-            <artifactId>jersey-servlet</artifactId>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-server</artifactId>
             <scope>test</scope>
         </dependency>
 

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayLocalServiceFuncTest.java
----------------------------------------------------------------------
diff --git a/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayLocalServiceFuncTest.java b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayLocalServiceFuncTest.java
new file mode 100644
index 0000000..c0800b5
--- /dev/null
+++ b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayLocalServiceFuncTest.java
@@ -0,0 +1,208 @@
+/**
+ * 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.hadoop.gateway;
+
+import com.mycila.xmltool.XMLDoc;
+import com.mycila.xmltool.XMLTag;
+import org.apache.commons.io.FileUtils;
+import org.apache.hadoop.gateway.config.GatewayConfig;
+import org.apache.hadoop.gateway.security.EmbeddedApacheDirectoryServer;
+import org.apache.hadoop.gateway.services.DefaultGatewayServices;
+import org.apache.hadoop.gateway.services.ServiceLifecycleException;
+import org.apache.hadoop.test.log.NoOpAppender;
+import org.apache.http.HttpStatus;
+import org.apache.log4j.Appender;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ServerSocket;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import static com.jayway.restassured.RestAssured.given;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+
+public class GatewayLocalServiceFuncTest {
+
+  private static Class RESOURCE_BASE_CLASS = GatewayLocalServiceFuncTest.class;
+  private static Logger LOG = LoggerFactory.getLogger( GatewayFuncTestDriver.class );
+
+  public static Enumeration<Appender> appenders;
+  public static GatewayConfig config;
+  public static GatewayServer gateway;
+  public static String gatewayUrl;
+  public static String clusterUrl;
+  public static EmbeddedApacheDirectoryServer ldap;
+
+  @BeforeClass
+  public static void setupSuite() throws Exception {
+    appenders = NoOpAppender.setUp();
+    setupLdap();
+    setupGateway();
+  }
+
+  @AfterClass
+  public static void cleanupSuite() throws Exception {
+    gateway.stop();
+    ldap.stop();
+    FileUtils.deleteQuietly( new File( config.getGatewayHomeDir() ) );
+    NoOpAppender.tearDown( appenders );
+  }
+
+  public static void setupLdap() throws Exception {
+    URL usersUrl = getResourceUrl( "users.ldif" );
+    int port = findFreePort();
+    ldap = new EmbeddedApacheDirectoryServer( "dc=hadoop,dc=apache,dc=org", null, port );
+    ldap.start();
+    ldap.loadLdif( usersUrl );
+    LOG.info( "LDAP port = " + ldap.getTransport().getPort() );
+  }
+
+  public static void setupGateway() throws IOException {
+
+    File targetDir = new File( System.getProperty( "user.dir" ), "target" );
+    File gatewayDir = new File( targetDir, "gateway-home-" + UUID.randomUUID() );
+    gatewayDir.mkdirs();
+
+    GatewayTestConfig testConfig = new GatewayTestConfig();
+    config = testConfig;
+    testConfig.setGatewayHomeDir( gatewayDir.getAbsolutePath() );
+    testConfig.setDeploymentDir( "clusters" );
+
+    File deployDir = new File( gatewayDir, testConfig.getDeploymentDir() );
+    deployDir.mkdirs();
+
+    File descriptor = new File( deployDir, "cluster.xml" );
+    FileOutputStream stream = new FileOutputStream( descriptor );
+    createTopology().toStream( stream );
+    stream.close();
+
+    DefaultGatewayServices srvcs = new DefaultGatewayServices();
+    Map<String,String> options = new HashMap<String,String>();
+    options.put( "persist-master", "false" );
+    options.put( "master", "password" );
+    try {
+      srvcs.init( testConfig, options );
+    } catch ( ServiceLifecycleException e ) {
+      e.printStackTrace(); // I18N not required.
+    }
+    gateway = GatewayServer.startGateway( testConfig, srvcs );
+    MatcherAssert.assertThat( "Failed to start gateway.", gateway, notNullValue() );
+
+    LOG.info( "Gateway port = " + gateway.getAddresses()[ 0 ].getPort() );
+
+    gatewayUrl = "http://localhost:" + gateway.getAddresses()[0].getPort() + "/" + config.getGatewayPath();
+    clusterUrl = gatewayUrl + "/cluster";
+  }
+
+  private static XMLTag createTopology() {
+    XMLTag xml = XMLDoc.newDocument( true )
+        .addRoot( "topology" )
+        .addTag( "gateway" )
+        .addTag( "provider" )
+        .addTag( "role" ).addText( "authentication" )
+        .addTag( "enabled" ).addText( "true" )
+        .addTag( "param" )
+        .addTag( "name" ).addText( "main.ldapRealm" )
+        .addTag( "value" ).addText( "org.apache.shiro.realm.ldap.JndiLdapRealm" ).gotoParent()
+        .addTag( "param" )
+        .addTag( "name" ).addText( "main.ldapRealm.userDnTemplate" )
+        .addTag( "value" ).addText( "uid={0},ou=people,dc=hadoop,dc=apache,dc=org" ).gotoParent()
+        .addTag( "param" )
+        .addTag( "name" ).addText( "main.ldapRealm.contextFactory.url" )
+        .addTag( "value" ).addText( "ldap://localhost:" + ldap.getTransport().getPort() ).gotoParent()
+        .addTag( "param" )
+        .addTag( "name" ).addText( "main.ldapRealm.contextFactory.authenticationMechanism" )
+        .addTag( "value" ).addText( "simple" ).gotoParent()
+        .addTag( "param" )
+        .addTag( "name" ).addText( "urls./**" )
+        .addTag( "value" ).addText( "authcBasic" ).gotoParent().gotoParent()
+        .addTag( "provider" )
+        .addTag( "role" ).addText( "identity-assertion" )
+        .addTag( "enabled" ).addText( "true" )
+        .addTag( "name" ).addText( "Pseudo" ).gotoParent()
+        .addTag( "provider" )
+        .gotoRoot()
+        .addTag( "service" )
+        .addTag( "role" ).addText( "test-jersey-service-role" )
+        .gotoRoot();
+    // System.out.println( "GATEWAY=" + xml.toString() );
+    return xml;
+  }
+
+  @Test
+  public void testJerseyService() throws ClassNotFoundException {
+    assertThat( ClassLoader.getSystemClassLoader().loadClass( "org.glassfish.jersey.servlet.ServletContainer" ), notNullValue() );
+    assertThat( ClassLoader.getSystemClassLoader().loadClass( "org.apache.hadoop.gateway.jersey.JerseyDispatchDeploymentContributor" ), notNullValue() );
+    assertThat( ClassLoader.getSystemClassLoader().loadClass( "org.apache.hadoop.gateway.jersey.JerseyServiceDeploymentContributorBase" ), notNullValue() );
+    assertThat( ClassLoader.getSystemClassLoader().loadClass( "org.apache.hadoop.gateway.TestJerseyService" ), notNullValue() );
+
+    String username = "guest";
+    String password = "guest-password";
+    String serviceUrl =  clusterUrl + "/test-jersey-service/test-jersey-resource-path";
+    given()
+        //.log().all()
+        .auth().preemptive().basic( username, password )
+        .expect()
+        //.log().all()
+        .statusCode( HttpStatus.SC_OK )
+        .contentType( "text/plain" )
+        .body( is( "test-jersey-resource-response" ) )
+        .when().get( serviceUrl );
+  }
+
+  private static int findFreePort() throws IOException {
+    ServerSocket socket = new ServerSocket(0);
+    int port = socket.getLocalPort();
+    socket.close();
+    return port;
+  }
+
+  public static InputStream getResourceStream( String resource ) throws IOException {
+    return getResourceUrl( resource ).openStream();
+  }
+
+  public static URL getResourceUrl( String resource ) {
+    URL url = ClassLoader.getSystemResource( getResourceName( resource ) );
+    assertThat( "Failed to find test resource " + resource, url, Matchers.notNullValue() );
+    return url;
+  }
+
+  public static String getResourceName( String resource ) {
+    return getResourceBaseName() + resource;
+  }
+
+  public static String getResourceBaseName() {
+    return RESOURCE_BASE_CLASS.getName().replaceAll( "\\.", "/" ) + "/";
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-test/src/test/java/org/apache/hadoop/gateway/TestJerseyService.java
----------------------------------------------------------------------
diff --git a/gateway-test/src/test/java/org/apache/hadoop/gateway/TestJerseyService.java b/gateway-test/src/test/java/org/apache/hadoop/gateway/TestJerseyService.java
new file mode 100644
index 0000000..b8a16d2
--- /dev/null
+++ b/gateway-test/src/test/java/org/apache/hadoop/gateway/TestJerseyService.java
@@ -0,0 +1,34 @@
+/**
+ * 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.hadoop.gateway;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path( "/test-jersey-service/test-jersey-resource-path" )
+public class TestJerseyService {
+
+  @GET
+  @Produces( MediaType.TEXT_PLAIN )
+  public String getResource() {
+    return "test-jersey-resource-response";
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-test/src/test/java/org/apache/hadoop/gateway/TestJerseyServiceDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-test/src/test/java/org/apache/hadoop/gateway/TestJerseyServiceDeploymentContributor.java b/gateway-test/src/test/java/org/apache/hadoop/gateway/TestJerseyServiceDeploymentContributor.java
new file mode 100644
index 0000000..209e577
--- /dev/null
+++ b/gateway-test/src/test/java/org/apache/hadoop/gateway/TestJerseyServiceDeploymentContributor.java
@@ -0,0 +1,44 @@
+/**
+ * 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.hadoop.gateway;
+
+import org.apache.hadoop.gateway.jersey.JerseyServiceDeploymentContributorBase;
+
+public class TestJerseyServiceDeploymentContributor extends JerseyServiceDeploymentContributorBase {
+
+  @Override
+  protected String[] getPackages() {
+    return new String[]{ "org.apache.hadoop.gateway" };
+  }
+
+  @Override
+  protected String[] getPatterns() {
+    return new String[]{ "test-jersey-service/**?**" };
+  }
+
+  @Override
+  public String getRole() {
+    return "test-jersey-service-role";
+  }
+
+  @Override
+  public String getName() {
+    return "test-jersey-service-name";
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-test/src/test/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ServiceDeploymentContributor
----------------------------------------------------------------------
diff --git a/gateway-test/src/test/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ServiceDeploymentContributor b/gateway-test/src/test/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ServiceDeploymentContributor
index 14e16ee..c271f26 100644
--- a/gateway-test/src/test/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ServiceDeploymentContributor
+++ b/gateway-test/src/test/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ServiceDeploymentContributor
@@ -16,4 +16,5 @@
 # limitations under the License.
 ##########################################################################
 
+org.apache.hadoop.gateway.TestJerseyServiceDeploymentContributor
 org.apache.hadoop.gateway.TestServiceDeploymentContributor
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/gateway-test/src/test/resources/org/apache/hadoop/gateway/GatewayLocalServiceFuncTest/users.ldif
----------------------------------------------------------------------
diff --git a/gateway-test/src/test/resources/org/apache/hadoop/gateway/GatewayLocalServiceFuncTest/users.ldif b/gateway-test/src/test/resources/org/apache/hadoop/gateway/GatewayLocalServiceFuncTest/users.ldif
new file mode 100644
index 0000000..fdd0296
--- /dev/null
+++ b/gateway-test/src/test/resources/org/apache/hadoop/gateway/GatewayLocalServiceFuncTest/users.ldif
@@ -0,0 +1,36 @@
+# 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.
+
+version: 1
+
+# entry for a sample people container
+# please replace with site specific values
+dn: ou=people,dc=hadoop,dc=apache,dc=org
+objectclass:top
+objectclass:organizationalUnit
+ou: people
+
+# entry for a sample end user
+# please replace with site specific values
+dn: uid=guest,ou=people,dc=hadoop,dc=apache,dc=org
+objectclass:top
+objectclass:person
+objectclass:organizationalPerson
+objectclass:inetOrgPerson
+cn: Guest
+sn: User
+uid: guest
+userPassword:guest-password
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/6a4101a0/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 255451a..3a52134 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,6 +39,8 @@
         <module>gateway-i18n-logging-log4j</module>
         <module>gateway-i18n-logging-sl4j</module>
         <module>gateway-spi</module>
+        <module>gateway-server</module>
+        <module>gateway-server-launcher</module>
         <module>gateway-provider-rewrite</module>
         <module>gateway-provider-rewrite-func-hostmap-static</module>
         <module>gateway-provider-rewrite-func-service-registry</module>
@@ -48,6 +50,7 @@
         <module>gateway-provider-security-shiro</module>
         <module>gateway-provider-security-authz-acls</module>
         <module>gateway-provider-identity-assertion-pseudo</module>
+        <module>gateway-provider-jersey</module>
         <module>gateway-service-as</module>
         <module>gateway-service-hbase</module>
         <module>gateway-service-hive</module>
@@ -55,8 +58,6 @@
         <module>gateway-service-oozie</module>
         <module>gateway-service-webhcat</module>
         <module>gateway-service-tgs</module>
-        <module>gateway-server</module>
-        <module>gateway-server-launcher</module>
         <module>gateway-shell</module>
         <module>gateway-shell-launcher</module>
         <module>gateway-release</module>
@@ -390,6 +391,11 @@
             </dependency>
             <dependency>
                 <groupId>${gateway-group}</groupId>
+                <artifactId>gateway-provider-jersey</artifactId>
+                <version>${gateway-version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${gateway-group}</groupId>
                 <artifactId>gateway-service-tgs</artifactId>
                 <version>${gateway-version}</version>
             </dependency>
@@ -461,6 +467,16 @@
                 <version>3.0.1</version>
             </dependency>
             -->
+            <dependency>
+                <groupId>org.glassfish.jersey.containers</groupId>
+                <artifactId>jersey-container-servlet</artifactId>
+                <version>2.4.1</version>
+            </dependency>
+            <dependency>
+                <groupId>org.glassfish.jersey.core</groupId>
+                <artifactId>jersey-server</artifactId>
+                <version>2.4</version>
+            </dependency>
 
             <dependency>
                 <groupId>org.eclipse.jetty</groupId>
@@ -827,6 +843,7 @@
                 <scope>test</scope>
             </dependency>
 
+            <!--
             <dependency>
                 <groupId>com.sun.jersey</groupId>
                 <artifactId>jersey-server</artifactId>
@@ -840,6 +857,7 @@
                 <version>1.14</version>
                 <scope>test</scope>
             </dependency>
+            -->
 
             <dependency>
                 <groupId>com.mycila.xmltool</groupId>