You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2017/09/08 15:15:15 UTC

[22/24] knox git commit: Merge branch 'master' into KNOX-998-Package_Restructuring

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthSSOTest.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthSSOTest.java
index 5babe90,0000000..8cfffb9
mode 100644,000000..100644
--- a/gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthSSOTest.java
+++ b/gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthSSOTest.java
@@@ -1,30 -1,0 +1,29 @@@
 +
 +/**
 + * 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.knox.gateway.provider.federation;
 +
- import junit.framework.TestCase;
 +
 +import org.junit.Test;
 +
- public class PreAuthSSOTest extends TestCase {
++public class PreAuthSSOTest extends org.junit.Assert {
 +  @Test
 +  public void testPreAuth() throws Exception {
 +    assertTrue(true);
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthServiceTest.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthServiceTest.java
index bf023e7,0000000..f42a8a3
mode 100644,000000..100644
--- a/gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthServiceTest.java
+++ b/gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthServiceTest.java
@@@ -1,115 -1,0 +1,114 @@@
 +/**
 + * 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.knox.gateway.provider.federation;
 +
 +import junit.framework.TestCase;
- import org.apache.knox.gateway.preauth.filter.*;
 +import org.apache.knox.gateway.preauth.filter.DefaultValidator;
 +import org.apache.knox.gateway.preauth.filter.IPValidator;
 +import org.apache.knox.gateway.preauth.filter.PreAuthService;
 +import org.apache.knox.gateway.preauth.filter.PreAuthValidationException;
 +import org.apache.knox.gateway.preauth.filter.PreAuthValidator;
 +import org.junit.Test;
 +
 +import javax.servlet.FilterConfig;
 +import javax.servlet.ServletException;
 +import javax.servlet.http.HttpServletRequest;
 +
 +import java.util.List;
 +import java.util.Map;
 +
 +import static org.mockito.Mockito.mock;
 +import static org.mockito.Mockito.when;
 +
- public class PreAuthServiceTest extends TestCase {
++public class PreAuthServiceTest extends org.junit.Assert {
 +
 +  @Test
 +  public void testValidatorMap() {
 +    Map<String, PreAuthValidator> valMap = PreAuthService.getValidatorMap();
 +    assertNotNull(valMap.get(IPValidator.IP_VALIDATION_METHOD_VALUE));
 +    assertEquals(valMap.get(IPValidator.IP_VALIDATION_METHOD_VALUE).getName(), IPValidator.IP_VALIDATION_METHOD_VALUE);
 +    assertNotNull(valMap.get(DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE));
 +    assertEquals(valMap.get(DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE).getName(), DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE);
 +
 +    //Negative test
 +    assertNull(valMap.get("NonExists"));
 +  }
 +
 +  @Test
 +  public void testDefaultValidator() throws ServletException,
 +      PreAuthValidationException {
 +    final HttpServletRequest request = mock(HttpServletRequest.class);
 +    final FilterConfig filterConfig = mock(FilterConfig.class);
 +    when(filterConfig.getInitParameter(PreAuthService.VALIDATION_METHOD_PARAM)).thenReturn
 +        (DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE);
 +    List<PreAuthValidator> validators = PreAuthService.getValidators(filterConfig);
 +    assertEquals(validators.size(), 1);
 +    assertEquals(validators.get(0).getName(), DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE);
 +    assertTrue(PreAuthService.validate(request, filterConfig, validators));
 +  }
 +
 +  @Test
 +  public void testIPValidator() throws ServletException, PreAuthValidationException {
 +    final HttpServletRequest request = mock(HttpServletRequest.class);
 +    when(request.getRemoteAddr()).thenReturn("10.1.23.42");
 +    final FilterConfig filterConfig = mock(FilterConfig.class);
 +    when(filterConfig.getInitParameter(IPValidator.IP_ADDRESSES_PARAM)).thenReturn("5.4.3.2,10.1.23.42");
 +    when(filterConfig.getInitParameter(PreAuthService.VALIDATION_METHOD_PARAM)).thenReturn(IPValidator
 +        .IP_VALIDATION_METHOD_VALUE);
 +    List<PreAuthValidator> validators = PreAuthService.getValidators(filterConfig);
 +    assertEquals(validators.size(), 1);
 +    assertEquals(validators.get(0).getName(), IPValidator.IP_VALIDATION_METHOD_VALUE);
 +    assertTrue(PreAuthService.validate(request, filterConfig, validators));
 +    //Negative testing
 +    when(request.getRemoteAddr()).thenReturn("10.10.22.33");
 +    assertFalse(PreAuthService.validate(request, filterConfig, validators));
 +  }
 +
 +  @Test
 +  public void testMultipleValidatorsPositive() throws ServletException, PreAuthValidationException {
 +    final HttpServletRequest request = mock(HttpServletRequest.class);
 +    when(request.getRemoteAddr()).thenReturn("10.1.23.42");
 +    final FilterConfig filterConfig = mock(FilterConfig.class);
 +    when(filterConfig.getInitParameter(IPValidator.IP_ADDRESSES_PARAM)).thenReturn("5.4.3.2,10.1.23.42");
 +    when(filterConfig.getInitParameter(PreAuthService.VALIDATION_METHOD_PARAM)).thenReturn
 +        (DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE + "," + IPValidator.IP_VALIDATION_METHOD_VALUE );
 +    List<PreAuthValidator> validators = PreAuthService.getValidators(filterConfig);
 +    assertEquals(validators.size(), 2);
 +    assertEquals(validators.get(0).getName(), DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE);
 +    assertEquals(validators.get(1).getName(), IPValidator.IP_VALIDATION_METHOD_VALUE);
 +
 +    assertTrue(PreAuthService.validate(request, filterConfig, validators));
 +    //Negative testing
 +    when(request.getRemoteAddr()).thenReturn("10.10.22.33");
 +    assertFalse(PreAuthService.validate(request, filterConfig, validators));
 +
 +  }
 +
 +  @Test
 +  public void testMultipleValidatorsNegative() throws ServletException, PreAuthValidationException {
 +    final FilterConfig filterConfig = mock(FilterConfig.class);
 +    when(filterConfig.getInitParameter(PreAuthService.VALIDATION_METHOD_PARAM)).thenReturn
 +        (DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE + ",  NOT_EXISTED_VALIDATOR" );
 +    try {
 +      PreAuthService.getValidators(filterConfig);
 +      fail("Should throw exception due to invalid validator");
 +    } catch (Exception e) {
 +      //Expected
 +    }
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-security-webappsec/src/main/java/org/apache/knox/gateway/webappsec/deploy/WebAppSecContributor.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-webappsec/src/main/java/org/apache/knox/gateway/webappsec/deploy/WebAppSecContributor.java
index 383dffe,0000000..a182b37
mode 100644,000000..100644
--- a/gateway-provider-security-webappsec/src/main/java/org/apache/knox/gateway/webappsec/deploy/WebAppSecContributor.java
+++ b/gateway-provider-security-webappsec/src/main/java/org/apache/knox/gateway/webappsec/deploy/WebAppSecContributor.java
@@@ -1,107 -1,0 +1,107 @@@
 +/**
 + * 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.knox.gateway.webappsec.deploy;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Map.Entry;
 +
 +import org.apache.knox.gateway.deploy.DeploymentContext;
 +import org.apache.knox.gateway.deploy.ProviderDeploymentContributorBase;
 +import org.apache.knox.gateway.descriptor.FilterParamDescriptor;
 +import org.apache.knox.gateway.descriptor.ResourceDescriptor;
 +import org.apache.knox.gateway.topology.Provider;
 +import org.apache.knox.gateway.topology.Service;
 +
 +public class WebAppSecContributor extends
 +    ProviderDeploymentContributorBase {
 +  private static final String ROLE = "webappsec";
 +  private static final String NAME = "WebAppSec";
 +  private static final String CSRF_SUFFIX = "_CSRF";
 +  private static final String CSRF_FILTER_CLASSNAME = "org.apache.knox.gateway.webappsec.filter.CSRFPreventionFilter";
 +  private static final String CSRF_ENABLED = "csrf.enabled";
 +  private static final String CORS_SUFFIX = "_CORS";
 +  private static final String CORS_FILTER_CLASSNAME = "com.thetransactioncompany.cors.CORSFilter";
 +  private static final String CORS_ENABLED = "cors.enabled";
 +  private static final String XFRAME_OPTIONS_SUFFIX = "_XFRAMEOPTIONS";
 +  private static final String XFRAME_OPTIONS_FILTER_CLASSNAME = "org.apache.knox.gateway.webappsec.filter.XFrameOptionsFilter";
 +  private static final String XFRAME_OPTIONS_ENABLED = "xframe.options.enabled";
 +
 +
 +  @Override
 +  public String getRole() {
 +    return ROLE;
 +  }
 +
 +  @Override
 +  public String getName() {
 +    return NAME;
 +  }
 +
 +  @Override
 +  public void initializeContribution(DeploymentContext context) {
 +    super.initializeContribution(context);
 +  }
 +
 +  @Override
 +  public void contributeFilter(DeploymentContext context, Provider provider, Service service, 
 +      ResourceDescriptor resource, List<FilterParamDescriptor> params) {
 +    
 +    Provider webappsec = context.getTopology().getProvider(ROLE, NAME);
 +    if (webappsec != null && webappsec.isEnabled()) {
 +      Map<String,String> map = provider.getParams();
 +      if (params == null) {
 +        params = new ArrayList<FilterParamDescriptor>();
 +      }
 +
 +      Map<String, String> providerParams = provider.getParams();
 +      // CORS support
 +      String corsEnabled = map.get(CORS_ENABLED);
-       if ( corsEnabled != null && corsEnabled.equals("true")) {
++      if ( corsEnabled != null && "true".equals(corsEnabled)) {
 +        provisionConfig(resource, providerParams, params, "cors.");
 +        resource.addFilter().name( getName() + CORS_SUFFIX ).role( getRole() ).impl( CORS_FILTER_CLASSNAME ).params( params );
 +      }
 +
 +      // CRSF
 +      params = new ArrayList<FilterParamDescriptor>();
 +      String csrfEnabled = map.get(CSRF_ENABLED);
-       if ( csrfEnabled != null && csrfEnabled.equals("true")) {
++      if ( csrfEnabled != null && "true".equals(csrfEnabled)) {
 +        provisionConfig(resource, providerParams, params, "csrf.");
 +        resource.addFilter().name( getName() + CSRF_SUFFIX ).role( getRole() ).impl( CSRF_FILTER_CLASSNAME ).params( params );
 +      }
 +
 +      // X-Frame-Options - clickjacking protection
 +      params = new ArrayList<FilterParamDescriptor>();
 +      String xframeOptionsEnabled = map.get(XFRAME_OPTIONS_ENABLED);
-       if ( xframeOptionsEnabled != null && xframeOptionsEnabled.equals("true")) {
++      if ( xframeOptionsEnabled != null && "true".equals(xframeOptionsEnabled)) {
 +        provisionConfig(resource, providerParams, params, "xframe.");
 +        resource.addFilter().name( getName() + XFRAME_OPTIONS_SUFFIX ).role( getRole() ).impl( XFRAME_OPTIONS_FILTER_CLASSNAME ).params( params );
 +      }
 +    }
 +  }
 +
 +  private void provisionConfig(ResourceDescriptor resource, Map<String,String> providerParams,
 +      List<FilterParamDescriptor> params, String prefix) {
 +    for(Entry<String, String> entry : providerParams.entrySet()) {
 +      if (entry.getKey().startsWith(prefix)) {
 +        params.add( resource.createFilterParam().name( entry.getKey().toLowerCase() ).value( entry.getValue() ) );
 +      }
 +    }
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/CSRFTest.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/CSRFTest.java
index f21d3c2,0000000..4f9ea33
mode 100644,000000..100644
--- a/gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/CSRFTest.java
+++ b/gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/CSRFTest.java
@@@ -1,29 -1,0 +1,28 @@@
 +/**
 + * 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.knox.gateway.webappsec;
 +
- import junit.framework.TestCase;
 +
 +import org.junit.Test;
 +
- public class CSRFTest extends TestCase {
++public class CSRFTest extends org.junit.Assert {
 +  @Test
 +  public void testCsrf() throws Exception {
 +    assertTrue(true);
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/XFrameOptionsFilterTest.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/XFrameOptionsFilterTest.java
index 2bb7bda,0000000..5a3c96f
mode 100644,000000..100644
--- a/gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/XFrameOptionsFilterTest.java
+++ b/gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/XFrameOptionsFilterTest.java
@@@ -1,193 -1,0 +1,193 @@@
 +/**
 + * 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.knox.gateway.webappsec;
 +
 +import static org.junit.Assert.fail;
 +
 +import java.io.IOException;
 +import java.util.Collection;
 +import java.util.Enumeration;
 +import java.util.Properties;
 +import javax.servlet.FilterChain;
 +import javax.servlet.FilterConfig;
 +import javax.servlet.ServletContext;
 +import javax.servlet.ServletException;
 +import javax.servlet.ServletRequest;
 +import javax.servlet.ServletResponse;
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpServletResponse;
 +
 +import org.apache.knox.gateway.webappsec.filter.XFrameOptionsFilter;
 +import org.easymock.EasyMock;
 +import org.junit.Assert;
 +import org.junit.Test;
 +
 +/**
 + *
 + */
 +public class XFrameOptionsFilterTest {
 +  /**
 +   * 
 +   */
 +  private static final String X_FRAME_OPTIONS = "X-Frame-Options";
 +  String options = null;
 +  Collection<String> headerNames = null;
 +  Collection<String> headers = null;
 +
 +  @Test
 +  public void testDefaultOptionsValue() throws Exception {
 +    try {
 +      XFrameOptionsFilter filter = new XFrameOptionsFilter();
 +      Properties props = new Properties();
 +      props.put("xframe.options.enabled", "true");
 +      filter.init(new TestFilterConfig(props));
 +
 +      HttpServletRequest request = EasyMock.createNiceMock(
 +          HttpServletRequest.class);
 +      HttpServletResponse response = EasyMock.createNiceMock(
 +          HttpServletResponse.class);
 +      EasyMock.replay(request);
 +      EasyMock.replay(response);
 +
 +      TestFilterChain chain = new TestFilterChain();
 +      filter.doFilter(request, response, chain);
 +      Assert.assertTrue("doFilterCalled should not be false.",
-           chain.doFilterCalled == true);
++          chain.doFilterCalled );
 +      Assert.assertTrue("Options value incorrect should be DENY but is: "
-           + options, options.equals("DENY"));
++          + options, "DENY".equals(options));
 +
 +      Assert.assertTrue("X-Frame-Options count not equal to 1.", headers.size() == 1);
 +    } catch (ServletException se) {
 +      fail("Should NOT have thrown a ServletException.");
 +    }
 +  }
 +
 +  @Test
 +  public void testConfiguredOptionsValue() throws Exception {
 +    try {
 +      XFrameOptionsFilter filter = new XFrameOptionsFilter();
 +      Properties props = new Properties();
 +      props.put("xframe.options.enabled", "true");
 +      props.put("xframe.options", "SAMEORIGIN");
 +      filter.init(new TestFilterConfig(props));
 +
 +      HttpServletRequest request = EasyMock.createNiceMock(
 +          HttpServletRequest.class);
 +      HttpServletResponse response = EasyMock.createNiceMock(
 +          HttpServletResponse.class);
 +      EasyMock.replay(request);
 +      EasyMock.replay(response);
 +
 +      TestFilterChain chain = new TestFilterChain();
 +      filter.doFilter(request, response, chain);
 +      Assert.assertTrue("doFilterCalled should not be false.",
-           chain.doFilterCalled == true);
++          chain.doFilterCalled );
 +      Assert.assertTrue("Options value incorrect should be SAMEORIGIN but is: "
-           + options, options.equals("SAMEORIGIN"));
++          + options, "SAMEORIGIN".equals(options));
 +
 +      Assert.assertTrue("X-Frame-Options count not equal to 1.", headers.size() == 1);
 +    } catch (ServletException se) {
 +      fail("Should NOT have thrown a ServletException.");
 +    }
 +  }
 +
 +//  @Test
 +//  public void testExistingXFrameOptionHeader() throws Exception {
 +//    try {
 +//      XFrameOptionsFilter filter = new XFrameOptionsFilter();
 +//      Properties props = new Properties();
 +//      props.put("xframe.options.enabled", "true");
 +//      props.put("xframe.options", "SAMEORIGIN");
 +//      filter.init(new TestFilterConfig(props));
 +//
 +//      HttpServletRequest request = EasyMock.createNiceMock(
 +//          HttpServletRequest.class);
 +//      HttpServletResponse response = EasyMock.createNiceMock(
 +//          HttpServletResponse.class);
 +//      EasyMock.replay(request);
 +//      EasyMock.replay(response);
 +//
 +//      TestFilterChain chain = new TestFilterChain();
 +//      filter.doFilter(request, response, chain);
 +//      Assert.assertTrue("doFilterCalled should not be false.",
- //          chain.doFilterCalled == true);
++//          chain.doFilterCalled );
 +//      Assert.assertTrue("Options value incorrect should be SAMEORIGIN but is: "
- //          + options, options.equals("SAMEORIGIN"));
++//          + options, "SAMEORIGIN".equals(options));
 +//
 +//      Assert.assertTrue("X-Frame-Options count not equal to 1.", headers.size() == 1);
 +//    } catch (ServletException se) {
 +//      fail("Should NOT have thrown a ServletException.");
 +//    }
 +//  }
 +
 +  class TestFilterConfig implements FilterConfig {
 +    Properties props = null;
 +
 +    public TestFilterConfig(Properties props) {
 +      this.props = props;
 +    }
 +
 +    @Override
 +    public String getFilterName() {
 +      return null;
 +    }
 +
 +    /* (non-Javadoc)
 +     * @see javax.servlet.FilterConfig#getServletContext()
 +     */
 +    @Override
 +    public ServletContext getServletContext() {
 +      return null;
 +    }
 +
 +    /* (non-Javadoc)
 +     * @see javax.servlet.FilterConfig#getInitParameter(java.lang.String)
 +     */
 +    @Override
 +    public String getInitParameter(String name) {
 +      return props.getProperty(name, null);
 +    }
 +
 +    /* (non-Javadoc)
 +     * @see javax.servlet.FilterConfig#getInitParameterNames()
 +     */
 +    @Override
 +    public Enumeration<String> getInitParameterNames() {
 +      return null;
 +    }
 +    
 +  }
 +
 +  class TestFilterChain implements FilterChain {
 +    boolean doFilterCalled = false;
 +
 +    /* (non-Javadoc)
 +     * @see javax.servlet.FilterChain#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
 +     */
 +    @Override
 +    public void doFilter(ServletRequest request, ServletResponse response)
 +        throws IOException, ServletException {
 +      doFilterCalled = true;
 +      options = ((HttpServletResponse)response).getHeader(X_FRAME_OPTIONS);
 +      headerNames = ((HttpServletResponse)response).getHeaderNames();
 +      headers = ((HttpServletResponse)response).getHeaders(X_FRAME_OPTIONS);
 +    }
 +    
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-release/home/conf/topologies/manager.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-server-xforwarded-filter/src/test/java/org/apache/knox/gateway/filter/CompositeEnumerationTest.java
----------------------------------------------------------------------
diff --cc gateway-server-xforwarded-filter/src/test/java/org/apache/knox/gateway/filter/CompositeEnumerationTest.java
index 25e9d5e,0000000..b069cb3
mode 100644,000000..100644
--- a/gateway-server-xforwarded-filter/src/test/java/org/apache/knox/gateway/filter/CompositeEnumerationTest.java
+++ b/gateway-server-xforwarded-filter/src/test/java/org/apache/knox/gateway/filter/CompositeEnumerationTest.java
@@@ -1,117 -1,0 +1,117 @@@
 +/**
 + * 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.knox.gateway.filter;
 +
 +import org.junit.Test;
 +
 +import java.util.Arrays;
 +import java.util.Collections;
 +import java.util.Enumeration;
 +import java.util.NoSuchElementException;
 +
- import static junit.framework.TestCase.fail;
 +import static org.hamcrest.CoreMatchers.is;
 +import static org.hamcrest.MatcherAssert.assertThat;
++import static org.junit.Assert.fail;
 +
 +public class CompositeEnumerationTest {
 +
 +  @Test
 +  public void testBasics() {
 +
 +    String[] a = new String[]{ "1", "2" };
 +    Enumeration<String> ea = Collections.enumeration( Arrays.asList( a ) );
 +
 +    String[] b = new String[]{ "3", "4" };
 +    Enumeration<String> eb = Collections.enumeration( Arrays.asList( b ) );
 +
 +    CompositeEnumeration<String> ce = new CompositeEnumeration<String>( ea, eb );
 +
 +    assertThat( ce.nextElement(), is( "1" ) );
 +    assertThat( ce.nextElement(), is( "2" ) );
 +    assertThat( ce.nextElement(), is( "3" ) );
 +    assertThat( ce.nextElement(), is( "4" ) );
 +    assertThat( ce.hasMoreElements(), is( false ) );
 +
 +  }
 +
 +  @Test
 +  public void testSingleValues() {
 +    String[] a = new String[]{ "1" };
 +    Enumeration<String> ea = Collections.enumeration( Arrays.asList( a ) );
 +
 +    String[] b = new String[]{ "2" };
 +    Enumeration<String> eb = Collections.enumeration( Arrays.asList( b ) );
 +
 +    CompositeEnumeration<String> ce = new CompositeEnumeration<String>( ea, eb );
 +
 +    assertThat( ce.nextElement(), is( "1" ) );
 +    assertThat( ce.nextElement(), is( "2" ) );
 +    assertThat( ce.hasMoreElements(), is( false ) );
 +  }
 +
 +  @Test
 +  public void testEmptyEnumerations() {
 +
 +    String[] a = new String[]{ "1", "2" };
 +    String[] b = new String[]{ "3", "4" };
 +    String[] c = new String[]{};
 +
 +    Enumeration<String> e1 = Collections.enumeration( Arrays.asList( a ) );
 +    Enumeration<String> e2 = Collections.enumeration( Arrays.asList( c ) );
 +    CompositeEnumeration<String> ce = new CompositeEnumeration<String>( e1, e2 );
 +    assertThat( ce.nextElement(), is( "1" ) );
 +    assertThat( ce.nextElement(), is( "2" ) );
 +    assertThat( ce.hasMoreElements(), is( false ) );
 +
 +    e1 = Collections.enumeration( Arrays.asList( c ) );
 +    e2 = Collections.enumeration( Arrays.asList( a ) );
 +    ce = new CompositeEnumeration<String>( e1, e2 );
 +    assertThat( ce.nextElement(), is( "1" ) );
 +    assertThat( ce.nextElement(), is( "2" ) );
 +    assertThat( ce.hasMoreElements(), is( false ) );
 +
 +    e1 = Collections.enumeration( Arrays.asList( c ) );
 +    e2 = Collections.enumeration( Arrays.asList( c ) );
 +    ce = new CompositeEnumeration<String>( e1, e2 );
 +    assertThat( ce.hasMoreElements(), is( false ) );
 +  }
 +
 +  @Test
 +  public void testEmpty() {
 +    CompositeEnumeration<String> ce = new CompositeEnumeration<String>();
 +    assertThat( ce.hasMoreElements(), is( false ) );
 +
 +    try {
 +      ce.nextElement();
 +      fail( "Should have throws NoSuchElementExcpetion" );
 +    } catch( NoSuchElementException e ) {
 +      // Expected.
 +    }
 +  }
 +
 +  @Test
 +  public void testNulls() {
 +    try {
 +      CompositeEnumeration<String> ce = new CompositeEnumeration<String>( null );
 +      fail( "Expected IllegalArgumentException" );
 +    } catch( IllegalArgumentException e ) {
 +      // Expected.
 +    }
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
----------------------------------------------------------------------
diff --cc gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
index 36c24de,0000000..70eca7f
mode 100644,000000..100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
@@@ -1,1029 -1,0 +1,1029 @@@
 +/**
 + * 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.knox.gateway;
 +
 +import net.lingala.zip4j.core.ZipFile;
 +import net.lingala.zip4j.exception.ZipException;
 +import org.apache.commons.cli.CommandLine;
 +import org.apache.commons.cli.ParseException;
 +import org.apache.commons.io.FileUtils;
 +import org.apache.commons.io.IOUtils;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.knox.gateway.audit.api.Action;
 +import org.apache.knox.gateway.audit.api.ActionOutcome;
 +import org.apache.knox.gateway.audit.api.AuditServiceFactory;
 +import org.apache.knox.gateway.audit.api.Auditor;
 +import org.apache.knox.gateway.audit.api.ResourceType;
 +import org.apache.knox.gateway.audit.log4j.audit.AuditConstants;
 +import org.apache.knox.gateway.config.GatewayConfig;
 +import org.apache.knox.gateway.config.impl.GatewayConfigImpl;
 +import org.apache.knox.gateway.deploy.DeploymentException;
 +import org.apache.knox.gateway.deploy.DeploymentFactory;
 +import org.apache.knox.gateway.filter.CorrelationHandler;
 +import org.apache.knox.gateway.filter.PortMappingHelperHandler;
 +import org.apache.knox.gateway.filter.RequestUpdateHandler;
 +import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 +import org.apache.knox.gateway.i18n.resources.ResourcesFactory;
 +import org.apache.knox.gateway.services.GatewayServices;
 +import org.apache.knox.gateway.services.registry.ServiceRegistry;
 +import org.apache.knox.gateway.services.security.SSLService;
 +import org.apache.knox.gateway.services.topology.TopologyService;
 +import org.apache.knox.gateway.topology.Application;
 +import org.apache.knox.gateway.topology.Topology;
 +import org.apache.knox.gateway.topology.TopologyEvent;
 +import org.apache.knox.gateway.topology.TopologyListener;
 +import org.apache.knox.gateway.trace.AccessHandler;
 +import org.apache.knox.gateway.trace.ErrorHandler;
 +import org.apache.knox.gateway.trace.TraceHandler;
 +import org.apache.knox.gateway.util.Urls;
 +import org.apache.knox.gateway.util.XmlUtils;
 +import org.apache.knox.gateway.websockets.GatewayWebsocketHandler;
 +import org.apache.log4j.PropertyConfigurator;
 +import org.eclipse.jetty.server.ConnectionFactory;
 +import org.eclipse.jetty.server.Connector;
 +import org.eclipse.jetty.server.HttpConfiguration;
 +import org.eclipse.jetty.server.HttpConnectionFactory;
 +import org.eclipse.jetty.server.NetworkConnector;
 +import org.eclipse.jetty.server.SecureRequestCustomizer;
 +import org.eclipse.jetty.server.Server;
 +import org.eclipse.jetty.server.ServerConnector;
 +import org.eclipse.jetty.server.handler.ContextHandler;
 +import org.eclipse.jetty.server.handler.ContextHandlerCollection;
 +import org.eclipse.jetty.server.handler.HandlerCollection;
 +import org.eclipse.jetty.server.handler.RequestLogHandler;
 +import org.eclipse.jetty.servlets.gzip.GzipHandler;
 +import org.eclipse.jetty.util.ssl.SslContextFactory;
 +import org.eclipse.jetty.util.thread.QueuedThreadPool;
 +import org.eclipse.jetty.webapp.Configuration;
 +import org.eclipse.jetty.webapp.WebAppContext;
 +import org.jboss.shrinkwrap.api.exporter.ExplodedExporter;
 +import org.jboss.shrinkwrap.api.spec.EnterpriseArchive;
 +import org.w3c.dom.Document;
 +import org.w3c.dom.Element;
 +import org.w3c.dom.Node;
 +import org.w3c.dom.NodeList;
 +import org.xml.sax.SAXException;
 +
 +import javax.xml.parsers.ParserConfigurationException;
 +import javax.xml.transform.TransformerException;
 +import java.io.File;
 +import java.io.FileWriter;
 +import java.io.FilenameFilter;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.Serializable;
 +import java.net.InetSocketAddress;
 +import java.net.ServerSocket;
 +import java.net.Socket;
 +import java.net.URI;
 +import java.net.URISyntaxException;
 +import java.net.UnknownHostException;
 +import java.security.KeyStoreException;
 +import java.security.NoSuchAlgorithmException;
 +import java.security.cert.CertificateException;
 +import java.util.ArrayList;
 +import java.util.Arrays;
 +import java.util.Collection;
 +import java.util.Comparator;
 +import java.util.HashMap;
 +import java.util.Iterator;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Properties;
 +import java.util.ServiceLoader;
 +import java.util.concurrent.ConcurrentHashMap;
 +import java.util.regex.Pattern;
 +
 +public class GatewayServer {
 +  private static final GatewayResources res = ResourcesFactory.get(GatewayResources.class);
 +  private static final GatewayMessages log = MessagesFactory.get(GatewayMessages.class);
 +  private static final Auditor auditor = AuditServiceFactory.getAuditService().getAuditor(AuditConstants.DEFAULT_AUDITOR_NAME,
 +      AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME);
 +  private static final String DEFAULT_CONNECTOR_NAME = "default";
 +
 +  private static GatewayServer server;
 +  private static GatewayServices services;
 +
 +  private static Properties buildProperties;
 +
 +  private Server jetty;
 +  private GatewayConfig config;
 +  private ContextHandlerCollection contexts;
 +  private TopologyService monitor;
 +  private TopologyListener listener;
 +  private Map<String, WebAppContext> deployments;
 +
 +  public static void main( String[] args ) {
 +    try {
 +      configureLogging();
 +      logSysProps();
 +      CommandLine cmd = GatewayCommandLine.parse( args );
 +      if( cmd.hasOption( GatewayCommandLine.HELP_LONG ) ) {
 +        GatewayCommandLine.printHelp();
 +      } else if( cmd.hasOption( GatewayCommandLine.VERSION_LONG ) ) {
 +        printVersion();
 +      } else if( cmd.hasOption( GatewayCommandLine.REDEPLOY_LONG  ) ) {
 +        redeployTopologies( cmd.getOptionValue( GatewayCommandLine.REDEPLOY_LONG ) );
 +      } else {
 +        buildProperties = loadBuildProperties();
 +        services = instantiateGatewayServices();
 +        if (services == null) {
 +          log.failedToInstantiateGatewayServices();
 +        }
 +        GatewayConfig config = new GatewayConfigImpl();
 +        if (config.isHadoopKerberosSecured()) {
 +          configureKerberosSecurity( config );
 +        }
 +        Map<String,String> options = new HashMap<>();
 +        options.put(GatewayCommandLine.PERSIST_LONG, Boolean.toString(cmd.hasOption(GatewayCommandLine.PERSIST_LONG)));
 +        services.init(config, options);
 +        if (!cmd.hasOption(GatewayCommandLine.NOSTART_LONG)) {
 +          startGateway( config, services );
 +        }
 +      }
 +    } catch ( ParseException e ) {
 +      log.failedToParseCommandLine( e );
 +      GatewayCommandLine.printHelp();
 +    } catch ( Exception e ) {
 +      log.failedToStartGateway( e );
 +      // Make sure the process exits.
 +      System.exit(1);
 +    }
 +  }
 +
 +  private static void printVersion() {
 +    System.out.println( res.gatewayVersionMessage( // I18N not required.
 +        getBuildVersion(),
 +        getBuildHash() ) );
 +  }
 +
 +  public static String getBuildHash() {
 +    String hash = "unknown";
 +    if( buildProperties != null ) {
 +      hash = buildProperties.getProperty( "build.hash", hash );
 +    }
 +    return hash;
 +  }
 +
 +  public static String getBuildVersion() {
 +    String version = "unknown";
 +    if( buildProperties != null ) {
 +      version = buildProperties.getProperty( "build.version", version );
 +    }
 +    return version;
 +  }
 +
 +  private static GatewayServices instantiateGatewayServices() {
 +    ServiceLoader<GatewayServices> loader = ServiceLoader.load( GatewayServices.class );
 +    Iterator<GatewayServices> services = loader.iterator();
 +    if (services.hasNext()) {
 +      return services.next();
 +    }
 +    return null;
 +  }
 +
 +  public static synchronized GatewayServices getGatewayServices() {
 +    return services;
 +  }
 +
 +  private static void logSysProp( String name ) {
 +    log.logSysProp( name, System.getProperty( name ) );
 +  }
 +
 +  private static void logSysProps() {
 +    logSysProp( "user.name" );
 +    logSysProp( "user.dir" );
 +    logSysProp( "java.runtime.name" );
 +    logSysProp( "java.runtime.version" );
 +    logSysProp( "java.home" );
 +  }
 +
 +  private static void configureLogging() {
 +    PropertyConfigurator.configure( System.getProperty( "log4j.configuration" ) );
 +//    String fileName = config.getGatewayConfDir() + File.separator + "log4j.properties";
 +//    File file = new File( fileName );
 +//    if( file.isFile() && file.canRead() ) {
 +//      FileInputStream stream;
 +//      try {
 +//        stream = new FileInputStream( file );
 +//        Properties properties = new Properties();
 +//        properties.load( stream );
 +//        PropertyConfigurator.configure( properties );
 +//        log.loadedLoggingConfig( fileName );
 +//      } catch( IOException e ) {
 +//        log.failedToLoadLoggingConfig( fileName );
 +//      }
 +//    }
 +  }
 +
 +  private static void configureKerberosSecurity( GatewayConfig config ) {
 +    System.setProperty(GatewayConfig.HADOOP_KERBEROS_SECURED, "true");
 +    System.setProperty(GatewayConfig.KRB5_CONFIG, config.getKerberosConfig());
 +    System.setProperty(GatewayConfig.KRB5_DEBUG,
 +        Boolean.toString(config.isKerberosDebugEnabled()));
 +    System.setProperty(GatewayConfig.KRB5_LOGIN_CONFIG, config.getKerberosLoginConfig());
 +    System.setProperty(GatewayConfig.KRB5_USE_SUBJECT_CREDS_ONLY,  "false");
 +  }
 +
 +  private static Properties loadBuildProperties() {
 +    Properties properties = new Properties();
 +    InputStream inputStream = GatewayServer.class.getClassLoader().getResourceAsStream( "build.properties" );
 +    if( inputStream != null ) {
 +      try {
 +        properties.load( inputStream );
 +        inputStream.close();
 +      } catch( IOException e ) {
 +        // Ignore.
 +      }
 +    }
 +    return properties;
 +  }
 +
 +  public static void redeployTopologies( String topologyName  ) {
 +    TopologyService ts = getGatewayServices().getService(GatewayServices.TOPOLOGY_SERVICE);
 +    ts.reloadTopologies();
 +    ts.redeployTopologies(topologyName);
 +  }
 +
 +  private void cleanupTopologyDeployments() {
 +    File deployDir = new File( config.getGatewayDeploymentDir() );
 +    TopologyService ts = getGatewayServices().getService(GatewayServices.TOPOLOGY_SERVICE);
 +    for( Topology topology : ts.getTopologies() ) {
 +      cleanupTopologyDeployments( deployDir, topology );
 +    }
 +  }
 +
 +  private void cleanupTopologyDeployments( File deployDir, Topology topology ) {
 +    log.cleanupDeployments( topology.getName() );
 +    File[] files = deployDir.listFiles( new RegexFilenameFilter( topology.getName() + "\\.(war|topo)\\.[0-9A-Fa-f]+" ) );
 +    if( files != null ) {
 +      Arrays.sort( files, new FileModificationTimeDescendingComparator() );
 +      int verLimit = config.getGatewayDeploymentsBackupVersionLimit();
 +      long ageLimit = config.getGatewayDeploymentsBackupAgeLimit();
 +      long keepTime = System.currentTimeMillis() - ageLimit;
 +      for( int i=1; i<files.length; i++ ) {
 +        File file = files[i];
 +        if( ( ( verLimit >= 0 ) && ( i > verLimit ) ) ||
 +            ( ( ageLimit >= 0 ) && ( file.lastModified() < keepTime ) ) ) {
 +          log.cleanupDeployment( file.getAbsolutePath() );
 +          FileUtils.deleteQuietly( file );
 +        }
 +      }
 +    }
 +  }
 +
 +  public static GatewayServer startGateway( GatewayConfig config, GatewayServices svcs ) throws Exception {
 +    log.startingGateway();
 +    server = new GatewayServer( config );
 +    synchronized ( server ) {
 +      //KM[ Commented this out because is causes problems with
 +      // multiple services instance used in a single test process.
 +      // I'm not sure what drive including this check though.
 +      //if (services == null) {
 +      services = svcs;
 +      //}
 +      //KM]
 +      services.start();
 +      DeploymentFactory.setGatewayServices(services);
 +      server.start();
 +      // Coverity CID 1352654
 +      URI uri = server.jetty.getURI();
 +
 +      // Logging for topology <-> port
 +      InetSocketAddress[] addresses = new InetSocketAddress[server.jetty
 +          .getConnectors().length];
 +      for (int i = 0, n = addresses.length; i < n; i++) {
 +        NetworkConnector connector = (NetworkConnector) server.jetty
 +            .getConnectors()[i];
 +        if (connector != null) {
 +          for(ConnectionFactory x  : connector.getConnectionFactories()) {
 +            if(x instanceof HttpConnectionFactory) {
 +                ((HttpConnectionFactory)x).getHttpConfiguration().setSendServerVersion(config.isGatewayServerHeaderEnabled());
 +            }
 +          }
 +          if (connector.getName() == null) {
 +            log.startedGateway(
 +                connector != null ? connector.getLocalPort() : -1);
 +          } else {
 +            log.startedGateway(connector != null ? connector.getName() : "",
 +                connector != null ? connector.getLocalPort() : -1);
 +          }
 +        }
 +      }
 +
 +      return server;
 +    }
 +  }
 +
 +  public GatewayServer( GatewayConfig config ) {
 +    this(config, null);
 +  }
 +
 +  public GatewayServer( GatewayConfig config, Properties options ) {
 +      this.config = config;
 +      this.listener = new InternalTopologyListener();
 +  }
 +
 +  /**
 +   * Create a connector for Gateway Server to listen on.
 +   *
 +   * @param server       Jetty server
 +   * @param config       GatewayConfig
 +   * @param port         If value is > 0 then the given value is used else we
 +   *                     use the port provided in GatewayConfig.
 +   * @param topologyName Connector name, only used when not null
 +   * @return
 +   * @throws IOException
 +   * @throws CertificateException
 +   * @throws NoSuchAlgorithmException
 +   * @throws KeyStoreException
 +   */
 +  private static Connector createConnector(final Server server,
 +      final GatewayConfig config, final int port, final String topologyName)
 +      throws IOException, CertificateException, NoSuchAlgorithmException,
 +      KeyStoreException {
 +
 +    ServerConnector connector;
 +
 +    // Determine the socket address and check availability.
 +    InetSocketAddress address = config.getGatewayAddress();
 +    checkAddressAvailability( address );
 +
 +    final int connectorPort = port > 0 ? port : address.getPort();
 +
 +    checkPortConflict(connectorPort, topologyName, config);
 +
 +    HttpConfiguration httpConfig = new HttpConfiguration();
 +    httpConfig.setRequestHeaderSize( config.getHttpServerRequestHeaderBuffer() );
 +    //httpConfig.setRequestBufferSize( config.getHttpServerRequestBuffer() );
 +    httpConfig.setResponseHeaderSize( config.getHttpServerResponseHeaderBuffer() );
 +    httpConfig.setOutputBufferSize( config.getHttpServerResponseBuffer() );
 +
 +    if (config.isSSLEnabled()) {
 +      HttpConfiguration httpsConfig = new HttpConfiguration( httpConfig );
 +      httpsConfig.setSecureScheme( "https" );
 +      httpsConfig.setSecurePort( connectorPort );
 +      httpsConfig.addCustomizer( new SecureRequestCustomizer() );
 +      SSLService ssl = services.getService("SSLService");
 +      String keystoreFileName = config.getGatewaySecurityDir() + File.separatorChar + "keystores" + File.separatorChar + "gateway.jks";
 +      SslContextFactory sslContextFactory = (SslContextFactory)ssl.buildSslContextFactory( keystoreFileName );
 +      connector = new ServerConnector( server, sslContextFactory, new HttpConnectionFactory( httpsConfig ) );
 +    } else {
 +      connector = new ServerConnector( server );
 +    }
 +    connector.setHost( address.getHostName() );
 +    connector.setPort( connectorPort );
 +
 +    if(!StringUtils.isBlank(topologyName)) {
 +      connector.setName(topologyName);
 +    }
 +
 +    long idleTimeout = config.getGatewayIdleTimeout();
 +    if (idleTimeout > 0l) {
 +      connector.setIdleTimeout(idleTimeout);
 +    }
 +
 +    return connector;
 +  }
 +
 +  private static HandlerCollection createHandlers(
 +      final GatewayConfig config,
 +      final GatewayServices services,
 +      final ContextHandlerCollection contexts,
 +      final Map<String, Integer> topologyPortMap) {
 +    HandlerCollection handlers = new HandlerCollection();
 +    RequestLogHandler logHandler = new RequestLogHandler();
 +
 +    logHandler.setRequestLog( new AccessHandler() );
 +
 +    TraceHandler traceHandler = new TraceHandler();
 +    traceHandler.setHandler( contexts );
 +    traceHandler.setTracedBodyFilter( System.getProperty( "org.apache.knox.gateway.trace.body.status.filter" ) );
 +
 +    CorrelationHandler correlationHandler = new CorrelationHandler();
 +    correlationHandler.setHandler( traceHandler );
 +
 +    /* KNOX-732: Handler for GZip compression */
 +    GzipHandler gzipHandler = new GzipHandler();
 +    String[] mimeTypes = {};
 +    if (config.getMimeTypesToCompress() != null
 +        && !config.getMimeTypesToCompress().isEmpty()) {
 +      mimeTypes = (String[]) config.getMimeTypesToCompress().toArray();
 +    }
 +    gzipHandler.addIncludedMimeTypes(mimeTypes);
 +    gzipHandler.setHandler(correlationHandler);
 +
 +    // Used to correct the {target} part of request with Topology Port Mapping feature
 +    final PortMappingHelperHandler portMappingHandler = new PortMappingHelperHandler(config);
 +    portMappingHandler.setHandler(gzipHandler);
 +
 +     // If topology to port mapping feature is enabled then we add new Handler {RequestForwardHandler}
 +     // to the chain, this handler listens on the configured port (in gateway-site.xml)
 +     // and simply forwards requests to the correct context path.
 +
 +     //  The reason for adding ContextHandler is so that we can add a connector
 +     // to it on which the handler listens (exclusively).
 +
 +
 +    if (config.isGatewayPortMappingEnabled()) {
 +
 +      for (final Map.Entry<String, Integer> entry : topologyPortMap
 +          .entrySet()) {
 +        log.createJettyHandler(entry.getKey());
 +        final ContextHandler topologyContextHandler = new ContextHandler();
 +
 +        final RequestUpdateHandler updateHandler = new RequestUpdateHandler(
 +            config, entry.getKey(), services);
 +
 +        topologyContextHandler.setHandler(updateHandler);
 +        topologyContextHandler.setVirtualHosts(
 +            new String[] { "@" + entry.getKey().toLowerCase() });
 +
 +        handlers.addHandler(topologyContextHandler);
 +      }
 +
 +    }
 +
 +    handlers.addHandler(logHandler);
 +
-     if (config.isWebsocketEnabled()) {      
++    if (config.isWebsocketEnabled()) {
 +      final GatewayWebsocketHandler websocketHandler = new GatewayWebsocketHandler(
 +          config, services);
 +      websocketHandler.setHandler(portMappingHandler);
 +
 +      handlers.addHandler(websocketHandler);
 +
 +    } else {
 +      handlers.addHandler(portMappingHandler);
 +    }
 +
 +    return handlers;
 +  }
 +
 +  /**
 +   * Sanity Check to make sure configured ports are free and there is not port
 +   * conflict.
 +   *
 +   * @param port
 +   * @param topologyName
 +   * @param config
 +   * @throws IOException
 +   */
 +  public static void checkPortConflict(final int port,
 +      final String topologyName, final GatewayConfig config)
 +      throws IOException {
 +
 +    // Throw an exception if port in use
 +    if (isPortInUse(port)) {
 +      if (topologyName == null) {
 +        log.portAlreadyInUse(port);
 +      } else {
 +        log.portAlreadyInUse(port, topologyName);
 +      }
 +      throw new IOException(String.format(" Port %d already in use. ", port));
 +    }
 +
 +    // if topology name is blank which means we have all topologies listening on this port
 +    if (StringUtils.isBlank(topologyName)) {
 +      // If we have Default Topology old and new configuration (Port Mapping) throw error.
-       if (config.getGatewayPortMappings().containsValue(new Integer(port))
++      if (config.getGatewayPortMappings().containsValue(Integer.valueOf(port))
 +          && !StringUtils.isBlank(config.getDefaultTopologyName())) {
 +        log.portAlreadyInUse(port);
 +        throw new IOException(String.format(
 +            " Please map port %d using either \"gateway.port.mapping.sandbox\" or "
 +                + "\"default.app.topology.name\" property, "
 +                + "specifying both is not a valid configuration. ",
 +            port));
 +      }
 +    } else {
 +      // Topology name is not blank so check amongst other ports if we have a conflict
 +      for (final Map.Entry<String, Integer> entry : config
 +          .getGatewayPortMappings().entrySet()) {
 +        if (entry.getKey().equalsIgnoreCase(topologyName)) {
 +          continue;
 +        }
 +
 +        if (entry.getValue() == port) {
 +          log.portAlreadyInUse(port, topologyName);
 +          throw new IOException(String.format(
 +              " Topologies %s and %s use the same port %d, ports for topologies (if defined) have to be unique. ",
 +              entry.getKey(), topologyName, port));
 +        }
 +
 +      }
 +
 +    }
 +
 +  }
 +
 +  private synchronized void start() throws Exception {
 +    // Create the global context handler.
 +    contexts = new ContextHandlerCollection();
 +
 +     // A map to keep track of current deployments by cluster name.
 +    deployments = new ConcurrentHashMap<>();
 +
 +    // Start Jetty.
 +    jetty = new Server( new QueuedThreadPool( config.getThreadPoolMax() ) );
 +
 +    /* topologyName is null because all topology listen on this port */
 +    jetty.addConnector( createConnector( jetty, config, config.getGatewayPort(), null) );
 +
 +
 +    // Add Annotations processing into the Jetty server to support JSPs
 +    Configuration.ClassList classlist = Configuration.ClassList.setServerDefault( jetty );
 +    classlist.addBefore(
 +        "org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
 +        "org.eclipse.jetty.annotations.AnnotationConfiguration" );
 +
 +    // Load the current topologies.
 +    File topologiesDir = calculateAbsoluteTopologiesDir();
 +    log.loadingTopologiesFromDirectory(topologiesDir.getAbsolutePath());
 +    monitor = services.getService(GatewayServices.TOPOLOGY_SERVICE);
 +    monitor.addTopologyChangeListener(listener);
 +    monitor.reloadTopologies();
 +
 +    final Collection<Topology> topologies = monitor.getTopologies();
 +    final Map<String, Integer> topologyPortMap = config.getGatewayPortMappings();
 +
 +    // List of all the topology that are deployed
 +    final List<String> deployedTopologyList = new ArrayList<String>();
 +
 +    for (final Topology t : topologies) {
 +      deployedTopologyList.add(t.getName());
 +    }
 +
 +
 +    // Check whether the configured topologies for port mapping exist, if not
 +    // log WARN message and continue
 +    checkMappedTopologiesExist(topologyPortMap, deployedTopologyList);
 +
 +    final HandlerCollection handlers = createHandlers( config, services, contexts, topologyPortMap);
 +
 +     // Check whether a topology wants dedicated port,
 +     // if yes then we create a connector that listens on the provided port.
 +
 +    log.gatewayTopologyPortMappingEnabled(config.isGatewayPortMappingEnabled());
 +    if (config.isGatewayPortMappingEnabled()) {
 +      for (Map.Entry<String, Integer> entry : topologyPortMap.entrySet()) {
 +        // Add connector for only valid topologies, i.e. deployed topologies.
 +        // and NOT for Default Topology listening on standard gateway port.
 +        if(deployedTopologyList.contains(entry.getKey()) && (entry.getValue().intValue() != config.getGatewayPort()) ) {
 +          log.createJettyConnector(entry.getKey().toLowerCase(), entry.getValue());
 +          jetty.addConnector(createConnector(jetty, config, entry.getValue(),
 +              entry.getKey().toLowerCase()));
 +        }
 +      }
 +    }
 +
 +    jetty.setHandler(handlers);
 +
 +    try {
 +      jetty.start();
 +    }
 +    catch (IOException e) {
 +      log.failedToStartGateway( e );
 +      throw e;
 +    }
 +
 +    cleanupTopologyDeployments();
 +
 +    // Start the topology monitor.
 +    log.monitoringTopologyChangesInDirectory(topologiesDir.getAbsolutePath());
 +    monitor.startMonitor();
 +  }
 +
 +  public synchronized void stop() throws Exception {
 +    log.stoppingGateway();
 +    services.stop();
 +    monitor.stopMonitor();
 +    jetty.stop();
 +    jetty.join();
 +    log.stoppedGateway();
 +  }
 +
 +  /**
 +   * Check whether a port is free
 +   *
 +   * @param port
 +   * @return true if port in use else false
 +   */
 +  public static boolean isPortInUse(final int port) {
 +
 +    Socket socket = null;
 +    try {
 +      socket = new Socket("localhost", port);
 +      return true;
 +    } catch (final UnknownHostException e) {
 +      return false;
 +    } catch (final IOException e) {
 +      return false;
 +    } finally {
 +      IOUtils.closeQuietly(socket);
 +    }
 +
 +  }
 +
 +  /**
 +   * Checks whether the topologies defined in gateway-xml as part of Topology
 +   * Port mapping feature exists. If it does not Log a message and move on.
 +   *
 +   * @param configTopologies
 +   * @param topologies
 +   * @return
 +   */
 +  private void checkMappedTopologiesExist(
 +      final Map<String, Integer> configTopologies,
 +      final List<String> topologies) throws IOException {
 +
 +    for(final Map.Entry<String, Integer> entry : configTopologies.entrySet()) {
 +
 +      // If the topologies defined in gateway-config.xml are not found in gateway
 +      if (!topologies.contains(entry.getKey())) {
 +        log.topologyPortMappingCannotFindTopology(entry.getKey(), entry.getValue());
 +      }
 +
 +    }
 +
 +  }
 +
 +  public URI getURI() {
 +    return jetty.getURI();
 +  }
 +
 +  public InetSocketAddress[] getAddresses() {
 +    InetSocketAddress[] addresses = new InetSocketAddress[ jetty.getConnectors().length ];
 +    for( int i=0, n=addresses.length; i<n; i++ ) {
 +      NetworkConnector connector = (NetworkConnector)jetty.getConnectors()[ i ];
 +      String host = connector.getHost();
 +      if( host == null ) {
 +        addresses[ i ] = new InetSocketAddress( connector.getLocalPort() );
 +      } else {
 +        addresses[ i ] = new InetSocketAddress( host, connector.getLocalPort() );
 +      }
 +    }
 +    return addresses;
 +  }
 +
 +  private ErrorHandler createErrorHandler() {
 +    ErrorHandler errorHandler = new ErrorHandler();
 +    errorHandler.setShowStacks( false );
 +    errorHandler.setTracedBodyFilter( System.getProperty( "org.apache.knox.gateway.trace.body.status.filter" ) );
 +    return errorHandler;
 +  }
 +
 +  private WebAppContext createWebAppContext( Topology topology, File warFile, String warPath ) throws IOException, ZipException, TransformerException, SAXException, ParserConfigurationException {
 +    String topoName = topology.getName();
 +    WebAppContext context = new WebAppContext();
 +    String contextPath;
 +    contextPath = "/" + Urls.trimLeadingAndTrailingSlashJoin( config.getGatewayPath(), topoName, warPath );
 +    context.setContextPath( contextPath );
 +    context.setWar( warFile.getAbsolutePath() );
 +    context.setAttribute( GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE, topoName );
 +    context.setAttribute( "org.apache.knox.gateway.frontend.uri", getFrontendUri( context, config ) );
 +    context.setAttribute( GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE, config );
 +    // Add support for JSPs.
 +    context.setAttribute(
 +        "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
 +        ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$" );
 +    context.setTempDirectory( FileUtils.getFile( warFile, "META-INF", "temp" ) );
 +    context.setErrorHandler( createErrorHandler() );
 +    context.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
 +
 +    return context;
 +  }
 +
 +  private static void explodeWar( File source, File target ) throws IOException, ZipException {
 +    if( source.isDirectory() ) {
 +      FileUtils.copyDirectory( source, target );
 +    } else {
 +      ZipFile zip = new ZipFile( source );
 +      zip.extractAll( target.getAbsolutePath() );
 +    }
 +  }
 +
 +  private void mergeWebXmlOverrides( File webInfDir ) throws IOException, SAXException, ParserConfigurationException, TransformerException {
 +    File webXmlFile = new File( webInfDir, "web.xml" );
 +    Document webXmlDoc;
 +    if( webXmlFile.exists() ) {
 +      // Backup original web.xml file.
 +      File originalWebXmlFile = new File( webInfDir, "original-web.xml" );
 +      FileUtils.copyFile( webXmlFile, originalWebXmlFile );
 +      webXmlDoc = XmlUtils.readXml( webXmlFile );
 +    } else {
 +      webXmlDoc = XmlUtils.createDocument();
 +      webXmlDoc.appendChild( webXmlDoc.createElement( "web-app" ) );
 +    }
 +    File overrideWebXmlFile = new File( webInfDir, "override-web.xml" );
 +    if( overrideWebXmlFile.exists() ) {
 +      Document overrideWebXmlDoc = XmlUtils.readXml( overrideWebXmlFile );
 +      Element originalRoot = webXmlDoc.getDocumentElement();
 +      Element overrideRoot = overrideWebXmlDoc.getDocumentElement();
 +      NodeList overrideNodes = overrideRoot.getChildNodes();
 +      for( int i = 0, n = overrideNodes.getLength(); i < n; i++ ) {
 +        Node overrideNode = overrideNodes.item( i );
 +        if( overrideNode.getNodeType() == Node.ELEMENT_NODE ) {
 +          Node importedNode = webXmlDoc.importNode( overrideNode, true );
 +          originalRoot.appendChild( importedNode );
 +        }
 +      }
-       
++
 +      XmlUtils.writeXml( webXmlDoc, new FileWriter(webXmlFile) );
 +    }
 +  }
 +
 +  private synchronized void internalDeployApplications( Topology topology, File topoDir ) throws IOException, ZipException, ParserConfigurationException, TransformerException, SAXException {
 +    if( topology != null ) {
 +      Collection<Application> applications = topology.getApplications();
 +      if( applications != null ) {
 +        for( Application application : applications ) {
 +          List<String> urls = application.getUrls();
 +          if( urls == null || urls.isEmpty() ) {
 +            internalDeployApplication( topology, topoDir, application, application.getName() );
 +          } else {
 +            for( String url : urls ) {
 +              internalDeployApplication( topology, topoDir, application, url );
 +            }
 +          }
 +        }
 +      }
 +    }
 +  }
 +
 +  private synchronized void internalDeployApplication( Topology topology, File topoDir, Application application, String url ) throws IOException, ZipException, TransformerException, SAXException, ParserConfigurationException {
 +    File appsDir = new File( config.getGatewayApplicationsDir() );
 +    File appDir = new File( appsDir, application.getName() );
 +    File[] implFiles = appDir.listFiles( new RegexFilenameFilter( "app|app\\..*" ) );
 +    if( implFiles == null || implFiles.length == 0 ) {
 +      throw new DeploymentException( "Failed to find application in " + appDir );
 +    }
 +    File implFile = implFiles[0];
 +    File warDir = new File( topoDir, Urls.encode( "/" + Urls.trimLeadingAndTrailingSlash( url ) ) );
 +    File webInfDir = new File( warDir, "WEB-INF" );
 +    explodeWar( implFile, warDir );
 +    mergeWebXmlOverrides( webInfDir );
 +    createArchiveTempDir( warDir );
 +  }
 +
 +  private synchronized void internalActivateTopology( Topology topology, File topoDir ) throws IOException, ZipException, ParserConfigurationException, TransformerException, SAXException {
 +    log.activatingTopology( topology.getName() );
 +    File[] files = topoDir.listFiles( new RegexFilenameFilter( "%.*" ) );
 +    if( files != null ) {
 +      for( File file : files ) {
 +        internalActivateArchive( topology, file );
 +      }
 +    }
 +  }
 +
 +  private synchronized void internalActivateArchive( Topology topology, File warDir ) throws IOException, ZipException, ParserConfigurationException, TransformerException, SAXException {
 +    log.activatingTopologyArchive( topology.getName(), warDir.getName() );
 +    try {
 +      WebAppContext newContext = createWebAppContext( topology, warDir, Urls.decode( warDir.getName() ) );
 +      WebAppContext oldContext = deployments.get( newContext.getContextPath() );
 +      deployments.put( newContext.getContextPath(), newContext );
 +      if( oldContext != null ) {
 +        contexts.removeHandler( oldContext );
 +      }
 +      contexts.addHandler( newContext );
 +      if( contexts.isRunning() && !newContext.isRunning() ) {
 +          newContext.start();
 +      }
 +
 +    } catch( Exception e ) {
 +      auditor.audit( Action.DEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.FAILURE );
 +      log.failedToDeployTopology( topology.getName(), e );
 +    }
 +  }
 +
 +
 +  private synchronized void internalDeactivateTopology( Topology topology ) {
 +
 +    log.deactivatingTopology( topology.getName() );
 +
 +    String topoName = topology.getName();
 +    String topoPath = "/" + Urls.trimLeadingAndTrailingSlashJoin( config.getGatewayPath(), topoName );
 +    String topoPathSlash = topoPath + "/";
 +
 +    ServiceRegistry sr = getGatewayServices().getService(GatewayServices.SERVICE_REGISTRY_SERVICE);
 +    if (sr != null) {
 +      sr.removeClusterServices( topoName );
 +    }
 +
 +    // Find all the deployed contexts we need to deactivate.
 +    List<WebAppContext> deactivate = new ArrayList<WebAppContext>();
 +    if( deployments != null ) {
 +      for( WebAppContext app : deployments.values() ) {
 +        String appPath = app.getContextPath();
 +        if( appPath.equals( topoPath ) || appPath.startsWith( topoPathSlash ) ) {
 +          deactivate.add( app );
 +        }
 +      }
 +    }
 +
 +    // Deactivate the required deployed contexts.
 +    for( WebAppContext context : deactivate ) {
 +      String contextPath = context.getContextPath();
 +      deployments.remove( contextPath );
 +      contexts.removeHandler( context );
 +      try {
 +        context.stop();
 +      } catch( Exception e ) {
 +        auditor.audit(Action.UNDEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.FAILURE);
 +        log.failedToUndeployTopology( topology.getName(), e );
 +      }
 +    }
 +    deactivate.clear();
 +
 +  }
 +
 +  // Using an inner class to hide the handleTopologyEvent method from consumers of GatewayServer.
 +  private class InternalTopologyListener implements TopologyListener {
 +
 +    @Override
 +    public void handleTopologyEvent( List<TopologyEvent> events ) {
 +      synchronized ( GatewayServer.this ) {
 +        for( TopologyEvent event : events ) {
 +          Topology topology = event.getTopology();
 +          File deployDir = calculateAbsoluteDeploymentsDir();
 +          if( event.getType().equals( TopologyEvent.Type.DELETED ) ) {
 +            handleDeleteDeployment(topology, deployDir);
 +          } else {
 +            handleCreateDeployment(topology, deployDir);
 +          }
 +        }
 +      }
 +    }
 +
 +    private void handleDeleteDeployment(Topology topology, File deployDir) {
 +      log.deletingTopology( topology.getName() );
 +      File[] files = deployDir.listFiles( new RegexFilenameFilter( topology.getName() + "\\.(war|topo)\\.[0-9A-Fa-f]+" ) );
 +      if( files != null ) {
 +        auditor.audit(Action.UNDEPLOY, topology.getName(), ResourceType.TOPOLOGY,
 +          ActionOutcome.UNAVAILABLE);
 +        internalDeactivateTopology( topology );
 +        for( File file : files ) {
 +          log.deletingDeployment( file.getAbsolutePath() );
 +          FileUtils.deleteQuietly( file );
 +        }
 +      }
 +    }
 +
 +    private void handleCreateDeployment(Topology topology, File deployDir) {
 +      try {
 +        File topoDir = calculateDeploymentDir( topology );
 +        if( !topoDir.exists() ) {
 +          auditor.audit( Action.DEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.UNAVAILABLE );
 +
 +//          KNOX-564 - Topology should fail to deploy with no providers configured.
 +//TODO:APPS:This should only fail if there are services in the topology.
 +          if(topology.getProviders().isEmpty()) {
 +            throw new DeploymentException("No providers found inside topology.");
 +          }
 +
 +          log.deployingTopology( topology.getName(), topoDir.getAbsolutePath() );
 +          internalDeactivateTopology( topology ); // KNOX-152
 +
 +          EnterpriseArchive ear = DeploymentFactory.createDeployment( config, topology );
 +          if( !deployDir.exists() && !deployDir.mkdirs() ) {
 +            throw new DeploymentException( "Failed to create topology deployment temporary directory: " + deployDir.getAbsolutePath() );
 +          }
 +          File tmp = ear.as( ExplodedExporter.class ).exportExploded( deployDir, topoDir.getName() + ".tmp" );
 +          if( !tmp.renameTo( topoDir ) ) {
 +            FileUtils.deleteQuietly( tmp );
 +            throw new DeploymentException( "Failed to create topology deployment directory: " + topoDir.getAbsolutePath() );
 +          }
 +          internalDeployApplications( topology, topoDir );
 +          internalActivateTopology( topology, topoDir );
 +          log.deployedTopology( topology.getName());
 +        } else {
 +          auditor.audit( Action.REDEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.UNAVAILABLE );
 +          log.redeployingTopology( topology.getName(), topoDir.getAbsolutePath() );
 +          internalActivateTopology( topology, topoDir );
 +          log.redeployedTopology( topology.getName() );
 +        }
 +        cleanupTopologyDeployments( deployDir, topology );
 +      } catch( Throwable e ) {
 +        auditor.audit( Action.DEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.FAILURE );
 +        log.failedToDeployTopology( topology.getName(), e );
 +      }
 +    }
 +
 +  }
 +
 +  private File createArchiveTempDir( File warDir ) {
 +    File tempDir = FileUtils.getFile( warDir, "META-INF", "temp" );
 +    if( !tempDir.exists() && !tempDir.mkdirs() ) {
 +      throw new DeploymentException( "Failed to create archive temporary directory: " + tempDir.getAbsolutePath() );
 +    }
 +    return tempDir;
 +  }
 +
 +  private static File calculateAbsoluteTopologiesDir( GatewayConfig config ) {
 +    File topoDir = new File( config.getGatewayTopologyDir() );
 +    topoDir = topoDir.getAbsoluteFile();
 +    return topoDir;
 +  }
 +
 +  private static File calculateAbsoluteDeploymentsDir( GatewayConfig config ) {
 +    File deployDir = new File( config.getGatewayDeploymentDir() );
 +    deployDir = deployDir.getAbsoluteFile();
 +    return deployDir;
 +  }
 +
 +  private File calculateAbsoluteTopologiesDir() {
 +    return calculateAbsoluteTopologiesDir( config );
 +  }
 +
 +  private File calculateAbsoluteDeploymentsDir() {
 +    return calculateAbsoluteDeploymentsDir( config );
 +  }
 +
 +  private File calculateDeploymentDir( Topology topology ) {
 +    File dir = new File( calculateAbsoluteDeploymentsDir(), calculateDeploymentName( topology ) );
 +    return dir;
 +  }
 +
 +  private String calculateDeploymentExtension( Topology topology ) {
 +    return ".topo.";
 +  }
 +
 +  private String calculateDeploymentName( Topology topology ) {
 +    String name = topology.getName() + calculateDeploymentExtension( topology ) + Long.toHexString( topology.getTimestamp() );
 +    return name;
 +  }
 +
 +  private static void checkAddressAvailability( InetSocketAddress address ) throws IOException {
 +    ServerSocket socket = new ServerSocket();
 +    socket.bind( address );
 +    socket.close();
 +  }
 +
 +  private static class RegexFilenameFilter implements FilenameFilter {
 +
 +    Pattern pattern;
 +
 +    RegexFilenameFilter( String regex ) {
 +      pattern = Pattern.compile( regex );
 +    }
 +
 +    @Override
 +    public boolean accept( File dir, String name ) {
 +      return pattern.matcher( name ).matches();
 +    }
 +  }
 +
 +  public URI getFrontendUri( WebAppContext context, GatewayConfig config ) {
 +    URI frontendUri = null;
 +    String frontendStr = config.getFrontendUrl();
 +    if( frontendStr != null && !frontendStr.trim().isEmpty() ) {
 +      String topoName = (String)context.getAttribute( GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE );
 +      try {
 +        frontendStr = frontendStr.trim();
 +        if( frontendStr.endsWith( "/" ) ) {
 +          frontendUri = new URI( frontendStr + topoName );
 +        } else {
 +          frontendUri = new URI( frontendStr + "/" + topoName );
 +        }
 +      } catch( URISyntaxException e ) {
 +        throw new IllegalArgumentException( e );
 +      }
 +    }
 +    return frontendUri;
 +  }
 +
 +  private static class FileModificationTimeDescendingComparator implements Comparator<File>, Serializable {
 +    /**
-      * 
++     *
 +     */
 +    private static final long serialVersionUID = -2269785204848916823L;
 +
 +    @Override
 +    public int compare( File left, File right ) {
 +      long leftTime = ( left == null ? Long.MIN_VALUE : left.lastModified() );
 +      long rightTime = ( right == null ? Long.MIN_VALUE : right.lastModified() );
 +      if( leftTime > rightTime ) {
 +        return -1;
 +      } else if ( leftTime < rightTime ) {
 +        return 1;
 +      } else {
 +        return 0;
 +      }
 +    }
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ApplicationDeploymentContributor.java
----------------------------------------------------------------------
diff --cc gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ApplicationDeploymentContributor.java
index 6b8574e,0000000..e02c0e5
mode 100644,000000..100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ApplicationDeploymentContributor.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ApplicationDeploymentContributor.java
@@@ -1,228 -1,0 +1,228 @@@
 +/**
 + * 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.knox.gateway.deploy.impl;
 +
 +import java.io.File;
 +import java.io.FileInputStream;
 +import java.io.FileNotFoundException;
 +import java.io.FileReader;
 +import java.io.IOException;
 +import java.io.StringReader;
 +import java.net.URISyntaxException;
 +import java.util.ArrayList;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +import javax.xml.bind.JAXBContext;
 +import javax.xml.bind.JAXBException;
 +import javax.xml.bind.Unmarshaller;
 +
 +import org.apache.knox.gateway.config.GatewayConfig;
 +import org.apache.knox.gateway.config.impl.GatewayConfigImpl;
 +import org.apache.knox.gateway.deploy.DeploymentContext;
 +import org.apache.knox.gateway.deploy.DeploymentException;
 +import org.apache.knox.gateway.deploy.ServiceDeploymentContributorBase;
 +import org.apache.knox.gateway.descriptor.FilterDescriptor;
 +import org.apache.knox.gateway.descriptor.FilterParamDescriptor;
 +import org.apache.knox.gateway.descriptor.ResourceDescriptor;
 +import org.apache.knox.gateway.filter.XForwardedHeaderFilter;
 +import org.apache.knox.gateway.filter.rewrite.api.CookieScopeServletFilter;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptorFactory;
 +import org.apache.knox.gateway.service.definition.Policy;
 +import org.apache.knox.gateway.service.definition.Rewrite;
 +import org.apache.knox.gateway.service.definition.Route;
 +import org.apache.knox.gateway.service.definition.ServiceDefinition;
 +import org.apache.knox.gateway.topology.Application;
 +import org.apache.knox.gateway.topology.Service;
 +import org.apache.knox.gateway.topology.Version;
 +
 +public class ApplicationDeploymentContributor extends ServiceDeploymentContributorBase {
 +
 +  private static final String SERVICE_DEFINITION_FILE_NAME = "service.xml";
 +  private static final String REWRITE_RULES_FILE_NAME = "rewrite.xml";
 +  private static final String XFORWARDED_FILTER_NAME = "XForwardedHeaderFilter";
 +  private static final String XFORWARDED_FILTER_ROLE = "xforwardedheaders";
 +  private static final String COOKIE_SCOPING_FILTER_NAME = "CookieScopeServletFilter";
 +  private static final String COOKIE_SCOPING_FILTER_ROLE = "cookiescopef";
 +
 +  private ServiceDefinition serviceDefinition;
 +
 +  private UrlRewriteRulesDescriptor serviceRules;
 +
 +  private static ServiceDefinition loadServiceDefinition( Application application, File file ) throws JAXBException, FileNotFoundException, IOException {
 +    ServiceDefinition definition;
 +    if( !file.exists() ) {
 +      definition = new ServiceDefinition();
 +      definition.setName( application.getName() );
 +      List<Route> routes = new ArrayList<Route>(1);
 +      Route route;
 +      route = new Route();
 +      route.setPath( "/?**" );
 +      routes.add( route );
 +      route = new Route();
 +      route.setPath( "/**?**" );
 +      routes.add( route );
 +      definition.setRoutes( routes );
 +    } else {
 +      JAXBContext context = JAXBContext.newInstance( ServiceDefinition.class );
 +      Unmarshaller unmarshaller = context.createUnmarshaller();
 +      try( FileInputStream inputStream = new FileInputStream( file ) ) {
 +          definition = (ServiceDefinition) unmarshaller.unmarshal( inputStream );
 +      }
 +    }
 +    return definition;
 +  }
 +
 +  private static UrlRewriteRulesDescriptor loadRewriteRules( Application application, File file ) throws IOException {
 +    UrlRewriteRulesDescriptor rules;
 +    if( !file.exists() ) {
 +      rules = UrlRewriteRulesDescriptorFactory.load( "xml", new StringReader( "<rules/>" ) );
 +    } else {
 +      FileReader reader = new FileReader( file );
 +      rules = UrlRewriteRulesDescriptorFactory.load( "xml", reader );
 +      reader.close();
 +    }
 +    return rules;
 +  }
 +
 +  public ApplicationDeploymentContributor( GatewayConfig config, Application application ) throws
 +      DeploymentException {
 +    try {
 +      File appsDir = new File( config.getGatewayApplicationsDir() );
 +      File appDir = new File( appsDir, application.getName() );
 +      File serviceFile = new File( appDir, SERVICE_DEFINITION_FILE_NAME );
 +      File rewriteFile = new File( appDir, REWRITE_RULES_FILE_NAME );
 +      serviceDefinition = loadServiceDefinition( application, serviceFile );
 +      serviceRules = loadRewriteRules( application, rewriteFile );
 +    } catch ( IOException e ) {
 +      throw new DeploymentException( "Failed to deploy application: " + application.getName(), e );
 +    } catch ( JAXBException e ){
 +      throw new DeploymentException( "Failed to deploy application: " + application.getName(), e );
 +    }
 +  }
 +
 +  @Override
 +  public String getRole() {
 +    return serviceDefinition.getRole();
 +  }
 +
 +  @Override
 +  public String getName() {
 +    return serviceDefinition.getName();
 +  }
 +
 +  @Override
 +  public Version getVersion() {
 +    return new Version(serviceDefinition.getVersion());
 +  }
 +
 +  @Override
 +  public void contributeService(DeploymentContext context, Service service) throws Exception {
 +    contributeRewriteRules(context, service);
 +    contributeResources(context, service);
 +  }
 +
 +  private void contributeRewriteRules(DeploymentContext context, Service service) {
 +    if ( serviceRules != null ) {
 +      UrlRewriteRulesDescriptor clusterRules = context.getDescriptor("rewrite");
 +      // Coverity CID 1352312
 +      if( clusterRules != null ) {
 +        clusterRules.addRules( serviceRules );
 +      }
 +    }
 +  }
 +
 +  private void contributeResources(DeploymentContext context, Service service) {
 +    Map<String, String> filterParams = new HashMap<>();
 +    List<Route> bindings = serviceDefinition.getRoutes();
 +    for ( Route binding : bindings ) {
 +      List<Rewrite> filters = binding.getRewrites();
 +      if ( filters != null && !filters.isEmpty() ) {
 +        filterParams.clear();
 +        for ( Rewrite filter : filters ) {
 +          filterParams.put(filter.getTo(), filter.getApply());
 +        }
 +      }
 +      try {
 +        contributeResource(context, service, binding, filterParams);
 +      } catch ( URISyntaxException e ) {
 +        e.printStackTrace();
 +      }
 +    }
 +
 +  }
 +
 +  private void contributeResource( DeploymentContext context, Service service, Route binding, Map<String, String> filterParams) throws URISyntaxException {
 +    List<FilterParamDescriptor> params = new ArrayList<FilterParamDescriptor>();
 +    ResourceDescriptor resource = context.getGatewayDescriptor().addResource();
 +    resource.role(service.getRole());
 +    resource.pattern(binding.getPath());
 +    //add x-forwarded filter if enabled in config
 +    if (context.getGatewayConfig().isXForwardedEnabled()) {
 +      resource.addFilter().name(XFORWARDED_FILTER_NAME).role(XFORWARDED_FILTER_ROLE).impl(XForwardedHeaderFilter.class);
 +    }
 +    if (context.getGatewayConfig().isCookieScopingToPathEnabled()) {
 +      FilterDescriptor filter = resource.addFilter().name(COOKIE_SCOPING_FILTER_NAME).role(COOKIE_SCOPING_FILTER_ROLE).impl(CookieScopeServletFilter.class);
 +      filter.param().name(GatewayConfigImpl.HTTP_PATH).value(context.getGatewayConfig().getGatewayPath());
 +    }
 +    List<Policy> policyBindings = binding.getPolicies();
 +    if ( policyBindings == null ) {
 +      policyBindings = serviceDefinition.getPolicies();
 +    }
 +    if ( policyBindings == null ) {
 +      //add default set
 +      addDefaultPolicies(context, service, filterParams, params, resource);
 +    } else {
 +      addPolicies(context, service, filterParams, params, resource, policyBindings);
 +    }
 +  }
 +
 +  private void addPolicies( DeploymentContext context, Service service, Map<String, String> filterParams, List<FilterParamDescriptor> params, ResourceDescriptor resource, List<Policy> policyBindings) throws URISyntaxException {
 +    for ( Policy policyBinding : policyBindings ) {
 +      String role = policyBinding.getRole();
 +      if ( role == null ) {
 +        throw new IllegalArgumentException("Policy defined has no role for service " + service.getName());
 +      }
 +      role = role.trim().toLowerCase();
-       if ( role.equals("rewrite") ) {
++      if ( "rewrite".equals(role) ) {
 +        addRewriteFilter(context, service, filterParams, params, resource);
 +      } else if ( topologyContainsProviderType(context, role) ) {
 +        context.contributeFilter(service, resource, role, policyBinding.getName(), null);
 +      }
 +    }
 +  }
 +
 +  private void addDefaultPolicies( DeploymentContext context, Service service, Map<String, String> filterParams, List<FilterParamDescriptor> params, ResourceDescriptor resource) throws URISyntaxException {
 +    addWebAppSecFilters(context, service, resource);
 +    addAuthenticationFilter(context, service, resource);
 +    addRewriteFilter(context, service, filterParams, params, resource);
 +    addIdentityAssertionFilter(context, service, resource);
 +    addAuthorizationFilter(context, service, resource);
 +  }
 +
 +  private void addRewriteFilter( DeploymentContext context, Service service, Map<String, String> filterParams, List<FilterParamDescriptor> params, ResourceDescriptor resource) throws URISyntaxException {
 +    if ( !filterParams.isEmpty() ) {
 +      for ( Map.Entry<String, String> filterParam : filterParams.entrySet() ) {
 +        params.add(resource.createFilterParam().name(filterParam.getKey()).value(filterParam.getValue()));
 +      }
 +    }
 +    addRewriteFilter(context, service, resource, params);
 +  }
 +
 +}