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/11/13 15:48:05 UTC

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

Merge branch 'master' into KNOX-998-Package_Restructuring

# Conflicts:
#	gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/beans/BeanConverter.java
#	gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultHttpClientFactory.java


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

Branch: refs/heads/KNOX-998-Package_Restructuring
Commit: 2c69152f49a22dbd6c9947a26965e3041a4f92d9
Parents: 1451428 d4b0dc6
Author: Sandeep More <mo...@apache.org>
Authored: Mon Nov 13 09:44:22 2017 -0500
Committer: Sandeep More <mo...@apache.org>
Committed: Mon Nov 13 09:44:22 2017 -0500

----------------------------------------------------------------------
 CHANGES                                         |  85 +++
 build.xml                                       |   2 +-
 gateway-applications/pom.xml                    |   2 +-
 gateway-demo-ldap-launcher/pom.xml              |   2 +-
 gateway-demo-ldap/pom.xml                       |   2 +-
 gateway-discovery-ambari/pom.xml                |   2 +-
 gateway-i18n-logging-log4j/pom.xml              |   2 +-
 gateway-i18n-logging-sl4j/pom.xml               |   2 +-
 gateway-i18n/pom.xml                            |   2 +-
 gateway-provider-ha/pom.xml                     |   2 +-
 .../ha/provider/impl/DefaultURLManagerTest.java |  19 +
 .../pom.xml                                     |   2 +-
 .../pom.xml                                     |   2 +-
 .../pom.xml                                     |   2 +-
 .../pom.xml                                     |   2 +-
 .../pom.xml                                     |   2 +-
 .../pom.xml                                     |   2 +-
 gateway-provider-jersey/pom.xml                 |   2 +-
 .../pom.xml                                     |   2 +-
 .../pom.xml                                     |   2 +-
 .../pom.xml                                     |   2 +-
 .../pom.xml                                     |   2 +-
 .../pom.xml                                     |   2 +-
 gateway-provider-rewrite/pom.xml                |   2 +-
 gateway-provider-security-authc-anon/pom.xml    |   2 +-
 gateway-provider-security-authz-acls/pom.xml    |   2 +-
 gateway-provider-security-hadoopauth/pom.xml    |   2 +-
 gateway-provider-security-jwt/pom.xml           |   2 +-
 gateway-provider-security-pac4j/pom.xml         |   2 +-
 gateway-provider-security-preauth/pom.xml       |   2 +-
 gateway-provider-security-shiro/pom.xml         |   2 +-
 gateway-provider-security-webappsec/pom.xml     |   2 +-
 gateway-release/pom.xml                         |   6 +-
 gateway-server-launcher/pom.xml                 |   2 +-
 gateway-server-xforwarded-filter/pom.xml        |   2 +-
 gateway-server/pom.xml                          |   2 +-
 .../knox/gateway/deploy/DeploymentFactory.java  |  23 +
 .../ServiceDefinitionDeploymentContributor.java |  14 +-
 .../instr/InstrHttpClientBuilderProvider.java   |   3 +-
 .../builder/BeanPropertyTopologyBuilder.java    |  11 +
 .../topology/simple/SimpleDescriptor.java       |  10 +
 .../simple/SimpleDescriptorHandler.java         |  51 +-
 .../topology/simple/SimpleDescriptorImpl.java   |  42 +-
 .../xml/KnoxFormatXmlTopologyRules.java         |   2 +
 .../src/main/resources/conf/topology-v1.xsd     |   1 +
 .../simple/SimpleDescriptorFactoryTest.java     | 631 +++++++++++++------
 .../simple/SimpleDescriptorHandlerTest.java     |   8 +
 gateway-service-admin/pom.xml                   |   4 +-
 .../service/admin/TopologiesResource.java       |  25 +-
 .../service/admin/beans/BeanConverter.java      |   2 +
 .../gateway/service/admin/beans/Topology.java   |  11 +
 gateway-service-as/pom.xml                      |   2 +-
 gateway-service-definitions/pom.xml             |   2 +-
 .../service/definition/CustomDispatch.java      |  11 +
 .../resources/services/livy/0.4.0/rewrite.xml   |  33 +
 .../resources/services/livy/0.4.0/service.xml   |  28 +
 .../resources/services/nifi/1.4.0/rewrite.xml   |  27 +
 .../resources/services/nifi/1.4.0/service.xml   |  30 +
 .../services/oozieui/4.2.0/rewrite.xml          |  27 +-
 gateway-service-hbase/pom.xml                   |   2 +-
 gateway-service-health/pom.xml                  |   4 +-
 gateway-service-hive/pom.xml                    |   2 +-
 gateway-service-knoxsso/pom.xml                 |   4 +-
 gateway-service-knoxssout/pom.xml               |   4 +-
 gateway-service-knoxtoken/pom.xml               |   4 +-
 gateway-service-nifi/pom.xml                    |  38 ++
 .../hadoop/gateway/dispatch/NiFiDispatch.java   | 106 ++++
 .../hadoop/gateway/dispatch/NiFiHaDispatch.java | 111 ++++
 .../hadoop/gateway/dispatch/NiFiHeaders.java    |  26 +
 .../gateway/dispatch/NiFiRequestUtil.java       |  89 +++
 .../gateway/dispatch/NiFiResponseUtil.java      |  89 +++
 gateway-service-rm/pom.xml                      |   2 +-
 gateway-service-storm/pom.xml                   |   2 +-
 gateway-service-test/pom.xml                    |   4 +-
 gateway-service-tgs/pom.xml                     |   2 +-
 gateway-service-vault/pom.xml                   |   4 +-
 gateway-service-webhdfs/pom.xml                 |   2 +-
 gateway-shell-launcher/pom.xml                  |   2 +-
 gateway-shell-release/pom.xml                   |   2 +-
 gateway-shell-samples/pom.xml                   |   2 +-
 gateway-shell/pom.xml                           |   2 +-
 gateway-spi/pom.xml                             |   6 +-
 .../dispatch/DefaultHttpClientFactory.java      |  55 +-
 .../knox/gateway/i18n/GatewaySpiMessages.java   |   3 +
 .../apache/knox/gateway/topology/Topology.java  |   9 +
 gateway-test-release-utils/pom.xml              |   2 +-
 gateway-test-release/pom.xml                    |   2 +-
 gateway-test-release/webhdfs-kerb-test/pom.xml  |   4 +-
 gateway-test-release/webhdfs-test/pom.xml       |   4 +-
 gateway-test-utils/pom.xml                      |   2 +-
 gateway-test/pom.xml                            |   2 +-
 .../deploy/DeploymentFactoryFuncTest.java       |   5 +
 gateway-util-common/pom.xml                     |   2 +-
 gateway-util-configinjector/pom.xml             |   2 +-
 gateway-util-launcher/pom.xml                   |   2 +-
 gateway-util-urltemplate/pom.xml                |   2 +-
 hadoop-examples/pom.xml                         |   2 +-
 knox-cli-launcher/pom.xml                       |   2 +-
 pom.xml                                         |  10 +-
 99 files changed, 1504 insertions(+), 289 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-demo-ldap-launcher/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-demo-ldap/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/DefaultURLManagerTest.java
----------------------------------------------------------------------
diff --cc gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/DefaultURLManagerTest.java
index c8b6c58,0000000..a2cfa54
mode 100644,000000..100644
--- a/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/DefaultURLManagerTest.java
+++ b/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/DefaultURLManagerTest.java
@@@ -1,73 -1,0 +1,92 @@@
 +/**
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS,
 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 + * See the License for the specific language governing permissions and
 + * limitations under the License.
 + */
 +package org.apache.knox.gateway.ha.provider.impl;
 +
 +import org.junit.Test;
 +
 +import java.util.ArrayList;
 +
 +import static org.junit.Assert.assertEquals;
 +import static org.junit.Assert.assertTrue;
 +
 +public class DefaultURLManagerTest {
 +
 +   @Test
 +   public void testActiveURLManagement() {
 +      ArrayList<String> urls = new ArrayList<>();
 +      String url1 = "http://host1";
 +      urls.add(url1);
 +      String url2 = "http://host2";
 +      urls.add(url2);
 +      DefaultURLManager manager = new DefaultURLManager();
 +      manager.setURLs(urls);
 +      assertTrue(manager.getURLs().containsAll(urls));
 +      assertEquals(url1, manager.getActiveURL());
 +      manager.markFailed(url1);
 +      assertEquals(url2, manager.getActiveURL());
 +      manager.markFailed(url2);
 +      assertEquals(url1, manager.getActiveURL());
 +   }
 +
++   /**
++    * KNOX-1104
++    * Verify that a service with HaProvider configuration, but only a single URL does not break the HaProvider.
++    */
++   @Test
++   public void testSingleURLManagement() {
++      ArrayList<String> urls = new ArrayList<>();
++      String url1 = "http://host1";
++      urls.add(url1);
++      DefaultURLManager manager = new DefaultURLManager();
++      manager.setURLs(urls);
++      assertTrue(manager.getURLs().containsAll(urls));
++      assertEquals(url1, manager.getActiveURL());
++      manager.markFailed(url1);
++      assertEquals(url1, manager.getActiveURL());
++      manager.markFailed(url1);
++      assertEquals(url1, manager.getActiveURL());
++   }
++
 +   @Test
 +   public void testMarkingFailedURL() {
 +      ArrayList<String> urls = new ArrayList<>();
 +      String url1 = "http://host1:4555";
 +      urls.add(url1);
 +      String url2 = "http://host2:1234";
 +      urls.add(url2);
 +      String url3 = "http://host1:1234";
 +      urls.add(url3);
 +      String url4 = "http://host2:4555";
 +      urls.add(url4);
 +      DefaultURLManager manager = new DefaultURLManager();
 +      manager.setURLs(urls);
 +      assertTrue(manager.getURLs().containsAll(urls));
 +      assertEquals(url1, manager.getActiveURL());
 +      manager.markFailed(url1);
 +      assertEquals(url2, manager.getActiveURL());
 +      manager.markFailed(url1);
 +      assertEquals(url2, manager.getActiveURL());
 +      manager.markFailed(url3);
 +      assertEquals(url2, manager.getActiveURL());
 +      manager.markFailed(url4);
 +      assertEquals(url2, manager.getActiveURL());
 +      manager.markFailed(url2);
 +      assertEquals(url3, manager.getActiveURL());
 +   }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-release/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-server-launcher/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-server/src/main/java/org/apache/knox/gateway/deploy/DeploymentFactory.java
----------------------------------------------------------------------
diff --cc gateway-server/src/main/java/org/apache/knox/gateway/deploy/DeploymentFactory.java
index bb8f1f2,0000000..b3eabb2
mode 100644,000000..100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/deploy/DeploymentFactory.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/deploy/DeploymentFactory.java
@@@ -1,772 -1,0 +1,795 @@@
 +/**
 + * 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;
 +
 +import java.beans.Statement;
 +import java.io.File;
 +import java.io.IOException;
 +import java.io.StringWriter;
 +import java.util.ArrayList;
 +import java.util.Collection;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.Iterator;
 +import java.util.LinkedHashMap;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Map.Entry;
 +import java.util.ServiceLoader;
 +import java.util.Set;
 +import java.util.TreeMap;
 +import javax.xml.bind.JAXBContext;
 +import javax.xml.bind.JAXBException;
 +import javax.xml.bind.Marshaller;
 +
 +import org.apache.knox.gateway.GatewayMessages;
 +import org.apache.knox.gateway.GatewayServlet;
 +import org.apache.knox.gateway.config.GatewayConfig;
 +import org.apache.knox.gateway.deploy.impl.ApplicationDeploymentContributor;
 +import org.apache.knox.gateway.descriptor.GatewayDescriptor;
 +import org.apache.knox.gateway.descriptor.GatewayDescriptorFactory;
 +import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 +import org.apache.knox.gateway.services.GatewayServices;
 +import org.apache.knox.gateway.services.registry.ServiceRegistry;
 +import org.apache.knox.gateway.topology.Application;
 +import org.apache.knox.gateway.topology.Provider;
 +import org.apache.knox.gateway.topology.Service;
 +import org.apache.knox.gateway.topology.Topology;
 +import org.apache.knox.gateway.topology.Version;
 +import org.apache.knox.gateway.util.ServiceDefinitionsLoader;
 +import org.apache.knox.gateway.util.Urls;
 +import org.jboss.shrinkwrap.api.ShrinkWrap;
 +import org.jboss.shrinkwrap.api.asset.Asset;
 +import org.jboss.shrinkwrap.api.asset.StringAsset;
 +import org.jboss.shrinkwrap.api.spec.EnterpriseArchive;
 +import org.jboss.shrinkwrap.api.spec.WebArchive;
 +import org.jboss.shrinkwrap.descriptor.api.Descriptors;
 +import org.jboss.shrinkwrap.descriptor.api.webapp30.WebAppDescriptor;
 +import org.jboss.shrinkwrap.descriptor.api.webcommon30.FilterType;
 +import org.jboss.shrinkwrap.descriptor.api.webcommon30.ServletType;
 +
 +public abstract class DeploymentFactory {
 +
 +  private static final String SERVLET_NAME_SUFFIX = "-knox-gateway-servlet";
 +  private static final String FILTER_NAME_SUFFIX = "-knox-gateway-filter";
 +  private static final GatewayMessages log = MessagesFactory.get( GatewayMessages.class );
 +  private static GatewayServices gatewayServices = null;
 +
 +  private static Map<String,Map<String,Map<Version, ServiceDeploymentContributor>>> SERVICE_CONTRIBUTOR_MAP;
 +  static {
 +    loadServiceContributors();
 +  }
 +
 +  private static Set<ProviderDeploymentContributor> PROVIDER_CONTRIBUTORS;
 +  private static Map<String,Map<String,ProviderDeploymentContributor>> PROVIDER_CONTRIBUTOR_MAP;
 +  static {
 +    loadProviderContributors();
 +  }
 +
 +  public static void setGatewayServices(GatewayServices services) {
 +    DeploymentFactory.gatewayServices = services;
 +  }
 +
 +  static List<Application> findApplicationsByUrl( Topology topology, String url ) {
 +    List<Application> foundApps = new ArrayList<Application>();
 +    if( topology != null ) {
 +      url = Urls.trimLeadingAndTrailingSlash( url );
 +      Collection<Application> searchApps = topology.getApplications();
 +      if( searchApps != null ) {
 +        for( Application searchApp : searchApps ) {
 +          List<String> searchUrls = searchApp.getUrls();
 +          if( searchUrls == null || searchUrls.isEmpty() ) {
 +            searchUrls = new ArrayList<String>(1);
 +            searchUrls.add( searchApp.getName() );
 +          }
 +          for( String searchUrl : searchUrls ) {
 +            if( url.equalsIgnoreCase( Urls.trimLeadingAndTrailingSlash( searchUrl ) ) ) {
 +              foundApps.add( searchApp );
 +              break;
 +            }
 +          }
 +        }
 +      }
 +    }
 +    return foundApps;
 +  }
 +
 +  // Verify that there are no two apps with duplicate urls.
 +  static void validateNoAppsWithDuplicateUrlsInTopology( Topology topology ) {
 +    if( topology != null ) {
 +      Collection<Application> apps = topology.getApplications();
 +      if( apps != null ) {
 +        for( Application app : apps ) {
 +          List<String> urls = app.getUrls();
 +          if( urls == null || urls.isEmpty() ) {
 +            urls = new ArrayList<String>(1);
 +            urls.add( app.getName() );
 +          }
 +          for( String url : urls ) {
 +            List<Application> dups = findApplicationsByUrl( topology, url );
 +            if( dups != null ) {
 +              for( Application dup : dups ) {
 +                if( dup != app ) {
 +                  throw new DeploymentException( "Topology " + topology.getName() + " contains applications " + app.getName() + " and " + dup.getName() + " with the same url: " + url );
 +                }
 +              }
 +            }
 +          }
 +        }
 +      }
 +    }
 +  }
 +
 +  // Verify that if there are services that there are no applications with a root url.
 +  static void validateNoAppsWithRootUrlsInServicesTopology( Topology topology ) {
 +    if( topology != null ) {
 +      if( topology.getServices() != null && !topology.getServices().isEmpty() ) {
 +        List<Application> dups = findApplicationsByUrl( topology, "/" );
 +        if( dups != null && !dups.isEmpty() ) {
 +          throw new DeploymentException( "Topology " + topology.getName() + " contains both services and an application " + dups.get( 0 ).getName() + " with a root url." );
 +        }
 +      }
 +    }
 +  }
 +
 +  static void validateTopology( Topology topology ) {
 +    validateNoAppsWithRootUrlsInServicesTopology( topology );
 +    validateNoAppsWithDuplicateUrlsInTopology( topology );
 +  }
 +
 +  public static EnterpriseArchive createDeployment( GatewayConfig config, Topology topology ) {
 +    validateTopology( topology );
 +    loadStacksServiceContributors( config );
 +    Map<String,List<ProviderDeploymentContributor>> providers = selectContextProviders( topology );
 +    Map<String,List<ServiceDeploymentContributor>> services = selectContextServices( topology );
 +    Map<String,ServiceDeploymentContributor> applications = selectContextApplications( config, topology );
 +    EnterpriseArchive ear = ShrinkWrap.create( EnterpriseArchive.class, topology.getName() );
 +    ear.addAsResource( toStringAsset( topology ), "topology.xml" );
 +    if( !services.isEmpty() ) {
 +      WebArchive war = createServicesDeployment( config, topology, providers, services );
 +      ear.addAsModule( war );
 +    }
 +    if( !applications.isEmpty() ) {
 +      for( Map.Entry<String, ServiceDeploymentContributor> application : applications.entrySet() ) {
 +        WebArchive war = createApplicationDeployment( config, topology, providers, application );
 +        ear.addAsModule( war );
 +      }
 +    }
 +    return ear;
 +  }
 +
 +  private static WebArchive createServicesDeployment(
 +      GatewayConfig config,
 +      Topology topology,
 +      Map<String,List<ProviderDeploymentContributor>> providers,
 +      Map<String,List<ServiceDeploymentContributor>> services ) {
 +    DeploymentContext context = createDeploymentContext( config, "/", topology, providers );
 +    initialize( context, providers, services, null );
 +    contribute( context, providers, services, null );
 +    finalize( context, providers, services, null );
 +    return context.getWebArchive();
 +  }
 +
 +  public static WebArchive createApplicationDeployment(
 +      GatewayConfig config,
 +      Topology topology,
 +      Map<String,List<ProviderDeploymentContributor>> providers,
 +      Map.Entry<String,ServiceDeploymentContributor> application ) {
 +    String appPath = "/" + Urls.trimLeadingAndTrailingSlash( application.getKey() );
 +    DeploymentContext context = createDeploymentContext( config, appPath, topology, providers );
 +    initialize( context, providers, null, application );
 +    contribute( context, providers, null, application );
 +    finalize( context, providers, null, application );
 +    return context.getWebArchive();
 +  }
 +
 +  private static Asset toStringAsset( Topology topology ) {
 +    StringWriter writer = new StringWriter();
 +    String xml;
 +    try {
 +      Map<String,Object> properties = new HashMap<>(2);
 +      properties.put( "eclipselink-oxm-xml",
 +          "org/apache/knox/gateway/topology/topology_binding-xml.xml");
 +      properties.put( "eclipselink.media-type", "application/xml" );
 +      JAXBContext jaxbContext = JAXBContext.newInstance( Topology.class.getPackage().getName(), Topology.class.getClassLoader() , properties );
 +      Marshaller marshaller = jaxbContext.createMarshaller();
 +      marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true );
 +      marshaller.marshal( topology, writer );
 +      writer.close();
 +      xml = writer.toString();
 +    } catch (IOException e) {
 +      throw new DeploymentException( "Failed to marshall topology.", e );
 +    } catch (JAXBException e) {
 +      throw new DeploymentException( "Failed to marshall topology.", e );
 +    }
 +    StringAsset asset = new StringAsset( xml );
 +    return asset;
 +  }
 +
 +  private static DeploymentContext createDeploymentContext(
 +      GatewayConfig config,
 +      String archivePath,
 +      Topology topology,
 +      Map<String,List<ProviderDeploymentContributor>> providers ) {
 +    archivePath = Urls.encode( archivePath );
 +    WebArchive webArchive = ShrinkWrap.create( WebArchive.class, archivePath );
 +    WebAppDescriptor webAppDesc = Descriptors.create( WebAppDescriptor.class );
 +    GatewayDescriptor gateway = GatewayDescriptorFactory.create();
 +    DeploymentContext context = new DeploymentContextImpl(
 +        config, topology, gateway, webArchive, webAppDesc, providers );
 +    return context;
 +  }
 +
 +  // Scan through the providers in the topology.  Collect any named providers in their roles list.
 +  // Scan through all of the loaded providers.  For each that doesn't have an existing provider in the role
 +  // list add it.
 +  private static Map<String,List<ProviderDeploymentContributor>> selectContextProviders( Topology topology ) {
 +    Map<String,List<ProviderDeploymentContributor>> providers = new LinkedHashMap<String, List<ProviderDeploymentContributor>>();
++    addMissingDefaultProviders(topology);
 +    collectTopologyProviders( topology, providers );
 +    collectDefaultProviders( providers );
 +    return providers;
 +  }
 +
++  private static void addMissingDefaultProviders(Topology topology) {
++    Collection<Provider> providers = topology.getProviders();
++    HashMap<String, String> providerMap = new HashMap<>();
++    for (Provider provider : providers) {
++      providerMap.put(provider.getRole(), provider.getName());
++    }
++    // first make sure that the required provider is available from the serviceloaders
++    // for some tests the number of providers are limited to the classpath of the module
++    // and exceptions will be thrown as topologies are deployed even though they will
++    // work fine at actual server runtime.
++    if (PROVIDER_CONTRIBUTOR_MAP.get("identity-assertion") != null) {
++      // check for required providers and add the defaults if missing
++      if (!providerMap.containsKey("identity-assertion")) {
++        Provider idassertion = new Provider();
++        idassertion.setRole("identity-assertion");
++        idassertion.setName("Default");
++        idassertion.setEnabled(true);
++        providers.add(idassertion);
++      }
++    }
++  }
++
 +  private static void collectTopologyProviders(
 +      Topology topology, Map<String, List<ProviderDeploymentContributor>> defaults ) {
 +    for( Provider provider : topology.getProviders() ) {
 +      String name = provider.getName();
 +      if( name != null ) {
 +        String role = provider.getRole();
 +        Map<String,ProviderDeploymentContributor> nameMap = PROVIDER_CONTRIBUTOR_MAP.get( role );
 +        if( nameMap != null ) {
 +          ProviderDeploymentContributor contributor = nameMap.get( name );
 +          // If there isn't a contributor with this role/name try to find a "*" contributor.
 +          if( contributor == null ) {
 +            nameMap = PROVIDER_CONTRIBUTOR_MAP.get( "*" );
 +            if( nameMap != null ) {
 +              contributor = nameMap.get( name );
 +            }
 +          }
 +          if( contributor != null ) {
 +            List list = defaults.get( role );
 +            if( list == null ) {
 +              list = new ArrayList( 1 );
 +              defaults.put( role, list );
 +            }
 +            if( !list.contains( contributor ) ) {
 +              list.add( contributor );
 +            }
 +          }
 +        }
 +      }
 +    }
 +  }
 +
 +  private static void collectDefaultProviders( Map<String,List<ProviderDeploymentContributor>> defaults ) {
 +    for( ProviderDeploymentContributor contributor : PROVIDER_CONTRIBUTORS ) {
 +      String role = contributor.getRole();
 +      List<ProviderDeploymentContributor> list = defaults.get( role );
 +      if( list == null ) {
 +        list = new ArrayList<ProviderDeploymentContributor>();
 +        defaults.put( role, list );
 +      }
 +      if( list.isEmpty() ) {
 +        list.add( contributor );
 +      }
 +    }
 +  }
 +
 +  // Scan through the services in the topology.
 +  // For each that we find add it to the list of service roles included in the topology.
 +  private static Map<String,List<ServiceDeploymentContributor>> selectContextServices( Topology topology ) {
 +    Map<String,List<ServiceDeploymentContributor>> defaults
 +        = new HashMap<>();
 +    for( Service service : topology.getServices() ) {
 +      String role = service.getRole();
 +      ServiceDeploymentContributor contributor = getServiceContributor( role, service.getName(), service.getVersion() );
 +      if( contributor != null ) {
 +        List<ServiceDeploymentContributor> list = defaults.get( role );
 +        if( list == null ) {
 +          list = new ArrayList<ServiceDeploymentContributor>( 1 );
 +          defaults.put( role, list );
 +        }
 +        if( !list.contains( contributor ) ) {
 +          list.add( contributor );
 +        }
 +      }
 +    }
 +    return defaults;
 +  }
 +
 +  private static Map<String,ServiceDeploymentContributor> selectContextApplications(
 +      GatewayConfig config, Topology topology ) {
 +    Map<String,ServiceDeploymentContributor> contributors = new HashMap<>();
 +    if( topology != null ) {
 +      for( Application application : topology.getApplications() ) {
 +        String name = application.getName();
 +        if( name == null || name.isEmpty() ) {
 +          throw new DeploymentException( "Topologies cannot contain an application without a name." );
 +        }
 +        ApplicationDeploymentContributor contributor = new ApplicationDeploymentContributor( config, application );
 +        List<String> urls = application.getUrls();
 +        if( urls == null || urls.isEmpty() ) {
 +          urls = new ArrayList<String>( 1 );
 +          urls.add( "/" + name );
 +        }
 +        for( String url : urls ) {
 +          if( url == null || url.isEmpty() || url.equals( "/" ) ) {
 +            if( !topology.getServices().isEmpty() ) {
 +              throw new DeploymentException( String.format(
 +                  "Topologies with services cannot contain an application (%s) with a root url.", name ) );
 +            }
 +          }
 +          contributors.put( url, contributor );
 +        }
 +      }
 +    }
 +    return contributors;
 +  }
 +
 +  private static void initialize(
 +      DeploymentContext context,
 +      Map<String,List<ProviderDeploymentContributor>> providers,
 +      Map<String,List<ServiceDeploymentContributor>> services,
 +      Map.Entry<String,ServiceDeploymentContributor> applications ) {
 +    WebAppDescriptor wad = context.getWebAppDescriptor();
 +    String topoName = context.getTopology().getName();
 +    if( applications == null ) {
 +      String servletName = topoName + SERVLET_NAME_SUFFIX;
 +      wad.createServlet().servletName( servletName ).servletClass( GatewayServlet.class.getName() );
 +      wad.createServletMapping().servletName( servletName ).urlPattern( "/*" );
 +    } else {
 +      String filterName = topoName + FILTER_NAME_SUFFIX;
 +      wad.createFilter().filterName( filterName ).filterClass( GatewayServlet.class.getName() );
 +      wad.createFilterMapping().filterName( filterName ).urlPattern( "/*" );
 +    }
 +    if (gatewayServices != null) {
 +      gatewayServices.initializeContribution(context);
 +    } else {
 +      log.gatewayServicesNotInitialized();
 +    }
 +    initializeProviders( context, providers );
 +    initializeServices( context, services );
 +    initializeApplications( context, applications );
 +  }
 +
 +  private static void initializeProviders(
 +      DeploymentContext context,
 +      Map<String,List<ProviderDeploymentContributor>> providers ) {
 +    if( providers != null ) {
 +      for( Entry<String, List<ProviderDeploymentContributor>> entry : providers.entrySet() ) {
 +        for( ProviderDeploymentContributor contributor : entry.getValue() ) {
 +          try {
 +            injectServices( contributor );
 +            log.initializeProvider( contributor.getName(), contributor.getRole() );
 +            contributor.initializeContribution( context );
 +          } catch( Exception e ) {
 +            log.failedToInitializeContribution( e );
 +            throw new DeploymentException( "Failed to initialize contribution.", e );
 +          }
 +        }
 +      }
 +    }
 +  }
 +
 +  private static void initializeServices( DeploymentContext context, Map<String, List<ServiceDeploymentContributor>> services ) {
 +    if( services != null ) {
 +      for( Entry<String, List<ServiceDeploymentContributor>> entry : services.entrySet() ) {
 +        for( ServiceDeploymentContributor contributor : entry.getValue() ) {
 +          try {
 +            injectServices( contributor );
 +            log.initializeService( contributor.getName(), contributor.getRole() );
 +            contributor.initializeContribution( context );
 +          } catch( Exception e ) {
 +            log.failedToInitializeContribution( e );
 +            throw new DeploymentException( "Failed to initialize contribution.", e );
 +          }
 +        }
 +      }
 +    }
 +  }
 +
 +  private static void initializeApplications( DeploymentContext context, Map.Entry<String, ServiceDeploymentContributor> application ) {
 +    if( application != null ) {
 +      ServiceDeploymentContributor contributor = application.getValue();
 +      if( contributor != null ) {
 +        try {
 +          injectServices( contributor );
 +          log.initializeApplication( contributor.getName() );
 +          contributor.initializeContribution( context );
 +        } catch( Exception e ) {
 +          log.failedToInitializeContribution( e );
 +          throw new DeploymentException( "Failed to initialize application contribution.", e );
 +        }
 +      }
 +    }
 +  }
 +
 +  private static void injectServices(Object contributor) {
 +    if (gatewayServices != null) {
 +      Statement stmt = null;
 +      for(String serviceName : gatewayServices.getServiceNames()) {
 +
 +        try {
 +          // TODO: this is just a temporary injection solution
 +          // TODO: test for the existence of the setter before attempting it
 +          // TODO: avoid exception throwing when there is no setter
 +          stmt = new Statement(contributor, "set" + serviceName, new Object[]{gatewayServices.getService(serviceName)});
 +          stmt.execute();
 +        } catch (NoSuchMethodException e) {
 +          // TODO: eliminate the possibility of this being thrown up front
 +        } catch (Exception e) {
 +          // Maybe it makes sense to throw exception
 +          log.failedToInjectService( serviceName, e );
 +          throw new DeploymentException("Failed to inject service.", e);
 +        }
 +      }
 +    }
 +  }
 +
 +  private static void contribute(
 +      DeploymentContext context,
 +      Map<String,List<ProviderDeploymentContributor>> providers,
 +      Map<String,List<ServiceDeploymentContributor>> services,
 +      Map.Entry<String,ServiceDeploymentContributor> applications ) {
 +    Topology topology = context.getTopology();
 +    contributeProviders( context, topology, providers );
 +    contributeServices( context, topology, services );
 +    contributeApplications( context, topology, applications );
 +  }
 +
 +  private static void contributeProviders( DeploymentContext context, Topology topology, Map<String, List<ProviderDeploymentContributor>> providers ) {
 +    for( Provider provider : topology.getProviders() ) {
 +      ProviderDeploymentContributor contributor = getProviderContributor( providers, provider.getRole(), provider.getName() );
 +      if( contributor != null && provider.isEnabled() ) {
 +        try {
 +          log.contributeProvider( provider.getName(), provider.getRole() );
 +          contributor.contributeProvider( context, provider );
 +        } catch( Exception e ) {
 +          // Maybe it makes sense to throw exception
 +          log.failedToContributeProvider( provider.getName(), provider.getRole(), e );
 +          throw new DeploymentException("Failed to contribute provider.", e);
 +        }
 +      }
 +    }
 +  }
 +
 +  private static void contributeServices( DeploymentContext context, Topology topology, Map<String, List<ServiceDeploymentContributor>> services ) {
 +    if( services != null ) {
 +      for( Service service : topology.getServices() ) {
 +        ServiceDeploymentContributor contributor = getServiceContributor( service.getRole(), service.getName(), service.getVersion() );
 +        if( contributor != null ) {
 +          try {
 +            log.contributeService( service.getName(), service.getRole() );
 +            contributor.contributeService( context, service );
 +            if( gatewayServices != null ) {
 +              ServiceRegistry sr = gatewayServices.getService( GatewayServices.SERVICE_REGISTRY_SERVICE );
 +              if( sr != null ) {
 +                String regCode = sr.getRegistrationCode( topology.getName() );
 +                sr.registerService( regCode, topology.getName(), service.getRole(), service.getUrls() );
 +              }
 +            }
 +          } catch( Exception e ) {
 +            // Maybe it makes sense to throw exception
 +            log.failedToContributeService( service.getName(), service.getRole(), e );
 +            throw new DeploymentException( "Failed to contribute service.", e );
 +          }
 +        }
 +      }
 +    }
 +  }
 +
 +  private static void contributeApplications( DeploymentContext context, Topology topology, Map.Entry<String, ServiceDeploymentContributor> applications ) {
 +    if( applications != null ) {
 +      ServiceDeploymentContributor contributor = applications.getValue();
 +      if( contributor != null ) {
 +        try {
 +          log.contributeApplication( contributor.getName() );
 +          Application applicationDesc = topology.getApplication( applications.getKey() );
 +          contributor.contributeService( context, applicationDesc );
 +        } catch( Exception e ) {
 +          log.failedToInitializeContribution( e );
 +          throw new DeploymentException( "Failed to contribution application.", e );
 +        }
 +      }
 +    }
 +  }
 +
 +  public static ProviderDeploymentContributor getProviderContributor( String role, String name ) {
 +    ProviderDeploymentContributor contributor = null;
 +    Map<String,ProviderDeploymentContributor> nameMap = PROVIDER_CONTRIBUTOR_MAP.get( role );
 +    if( nameMap != null ) {
 +      if( name != null ) {
 +        contributor = nameMap.get( name );
 +      } else if ( !nameMap.isEmpty() ) {
 +        contributor = nameMap.values().iterator().next();
 +      }
 +    }
 +    return contributor;
 +  }
 +
 +  public static ServiceDeploymentContributor getServiceContributor( String role, String name, Version version ) {
 +    ServiceDeploymentContributor contributor = null;
 +    Map<String,Map<Version, ServiceDeploymentContributor>> nameMap = SERVICE_CONTRIBUTOR_MAP.get( role );
 +    if( nameMap != null && !nameMap.isEmpty()) {
 +      Map<Version, ServiceDeploymentContributor> versionMap = null;
 +      if ( name == null ) {
 +        versionMap = nameMap.values().iterator().next();
 +      } else {
 +        versionMap = nameMap.get( name );
 +      }
 +      if ( versionMap != null && !versionMap.isEmpty()) {
 +        if( version == null ) {
 +          contributor = ((TreeMap<Version, ServiceDeploymentContributor>) versionMap).firstEntry().getValue();
 +        } else {
 +          contributor = versionMap.get( version );
 +        }
 +      }
 +    }
 +    return contributor;
 +  }
 +
 +  private static void finalize(
 +      DeploymentContext context,
 +      Map<String,List<ProviderDeploymentContributor>> providers,
 +      Map<String,List<ServiceDeploymentContributor>> services,
 +      Map.Entry<String,ServiceDeploymentContributor> application ) {
 +    try {
 +      // Write the gateway descriptor (gateway.xml) into the war.
 +      StringWriter writer = new StringWriter();
 +      GatewayDescriptorFactory.store( context.getGatewayDescriptor(), "xml", writer );
 +      context.getWebArchive().addAsWebInfResource(
 +          new StringAsset( writer.toString() ),
 +          GatewayServlet.GATEWAY_DESCRIPTOR_LOCATION_DEFAULT );
 +
 +      // Set the location of the gateway descriptor as a servlet init param.
 +      if( application == null ) {
 +        String servletName = context.getTopology().getName() + SERVLET_NAME_SUFFIX;
 +        ServletType<WebAppDescriptor> servlet = findServlet( context, servletName );
 +        // Coverity CID 1352314
 +        if( servlet == null ) {
 +          throw new DeploymentException( "Missing servlet " + servletName );
 +        } else {
 +          servlet.createInitParam()
 +              .paramName( GatewayServlet.GATEWAY_DESCRIPTOR_LOCATION_PARAM )
 +              .paramValue( "/WEB-INF/" + GatewayServlet.GATEWAY_DESCRIPTOR_LOCATION_DEFAULT );
 +        }
 +      } else {
 +        String servletName = context.getTopology().getName() + FILTER_NAME_SUFFIX;
 +        FilterType<WebAppDescriptor> filter = findFilter( context, servletName );
 +        // Coverity CID 1352313
 +        if( filter == null ) {
 +          throw new DeploymentException( "Missing filter " + servletName );
 +        } else {
 +          filter.createInitParam()
 +              .paramName( GatewayServlet.GATEWAY_DESCRIPTOR_LOCATION_PARAM )
 +              .paramValue( "/WEB-INF/" + GatewayServlet.GATEWAY_DESCRIPTOR_LOCATION_DEFAULT );
 +        }
 +      }
 +      if (gatewayServices != null) {
 +        gatewayServices.finalizeContribution(context);
 +      }
 +      finalizeProviders( context, providers );
 +      finalizeServices( context, services );
 +      finalizeApplications( context, application );
 +      writeDeploymentDescriptor( context, application != null );
 +    } catch ( IOException e ) {
 +      throw new RuntimeException( e );
 +    }
 +  }
 +
 +  private static void finalizeProviders( DeploymentContext context, Map<String, List<ProviderDeploymentContributor>> providers ) {
 +    if( providers != null ) {
 +      for( Entry<String, List<ProviderDeploymentContributor>> entry : providers.entrySet() ) {
 +        for( ProviderDeploymentContributor contributor : entry.getValue() ) {
 +          try {
 +            log.finalizeProvider( contributor.getName(), contributor.getRole() );
 +            contributor.finalizeContribution( context );
 +          } catch( Exception e ) {
 +            // Maybe it makes sense to throw exception
 +            log.failedToFinalizeContribution( e );
 +            throw new DeploymentException( "Failed to finalize contribution.", e );
 +          }
 +        }
 +      }
 +    }
 +  }
 +
 +  private static void finalizeServices( DeploymentContext context, Map<String, List<ServiceDeploymentContributor>> services ) {
 +    if( services != null ) {
 +      for( Entry<String, List<ServiceDeploymentContributor>> entry : services.entrySet() ) {
 +        for( ServiceDeploymentContributor contributor : entry.getValue() ) {
 +          try {
 +            log.finalizeService( contributor.getName(), contributor.getRole() );
 +            contributor.finalizeContribution( context );
 +          } catch( Exception e ) {
 +            // Maybe it makes sense to throw exception
 +            log.failedToFinalizeContribution( e );
 +            throw new DeploymentException( "Failed to finalize contribution.", e );
 +          }
 +        }
 +      }
 +    }
 +  }
 +
 +  private static void finalizeApplications( DeploymentContext context, Map.Entry<String, ServiceDeploymentContributor> application ) {
 +    if( application != null ) {
 +      ServiceDeploymentContributor contributor = application.getValue();
 +      if( contributor != null ) {
 +        try {
 +          log.finalizeApplication( contributor.getName() );
 +          contributor.finalizeContribution( context );
 +        } catch( Exception e ) {
 +          log.failedToInitializeContribution( e );
 +          throw new DeploymentException( "Failed to contribution application.", e );
 +        }
 +      }
 +    }
 +  }
 +
 +  private static void writeDeploymentDescriptor( DeploymentContext context, boolean override ) {
 +    // Write the web.xml into the war.
 +    Asset webXmlAsset = new StringAsset( context.getWebAppDescriptor().exportAsString() );
 +    if( override ) {
 +      context.getWebArchive().addAsWebInfResource( webXmlAsset, "override-web.xml" );
 +    } else {
 +      context.getWebArchive().setWebXML( webXmlAsset );
 +    }
 +  }
 +
 +  public static ServletType<WebAppDescriptor> findServlet( DeploymentContext context, String name ) {
 +    List<ServletType<WebAppDescriptor>> servlets = context.getWebAppDescriptor().getAllServlet();
 +    for( ServletType<WebAppDescriptor> servlet : servlets ) {
 +      if( name.equals( servlet.getServletName() ) ) {
 +        return servlet;
 +      }
 +    }
 +    return null;
 +  }
 +
 +  public static FilterType<WebAppDescriptor> findFilter( DeploymentContext context, String name ) {
 +    List<FilterType<WebAppDescriptor>> filters = context.getWebAppDescriptor().getAllFilter();
 +    for( FilterType<WebAppDescriptor> filter : filters ) {
 +      if( name.equals( filter.getFilterName() ) ) {
 +        return filter;
 +      }
 +    }
 +    return null;
 +  }
 +
 +  private static void loadStacksServiceContributors( GatewayConfig config ) {
 +    String stacks = config.getGatewayServicesDir();
 +    log.usingServicesDirectory(stacks);
 +    File stacksDir = new File(stacks);
 +    Set<ServiceDeploymentContributor> deploymentContributors = ServiceDefinitionsLoader
 +        .loadServiceDefinitions(stacksDir);
 +    addServiceDeploymentContributors(deploymentContributors.iterator());
 +  }
 +
 +  private static void loadServiceContributors() {
 +    SERVICE_CONTRIBUTOR_MAP = new HashMap<>();
 +    ServiceLoader<ServiceDeploymentContributor> loader = ServiceLoader.load( ServiceDeploymentContributor.class );
 +    Iterator<ServiceDeploymentContributor> contributors = loader.iterator();
 +    addServiceDeploymentContributors(contributors);
 +  }
 +
 +   private static void addServiceDeploymentContributors(Iterator<ServiceDeploymentContributor> contributors) {
 +      while( contributors.hasNext() ) {
 +        ServiceDeploymentContributor contributor = contributors.next();
 +        if( contributor.getName() == null ) {
 +          log.ignoringServiceContributorWithMissingName( contributor.getClass().getName() );
 +          continue;
 +        }
 +        if( contributor.getRole() == null ) {
 +          log.ignoringServiceContributorWithMissingRole( contributor.getClass().getName() );
 +          continue;
 +        }
 +        if( contributor.getVersion() == null ) {
 +          log.ignoringServiceContributorWithMissingVersion(contributor.getClass().getName());
 +          continue;
 +        }
 +        Map<String,Map<Version, ServiceDeploymentContributor>> nameMap = SERVICE_CONTRIBUTOR_MAP.get( contributor.getRole() );
 +        if( nameMap == null ) {
 +          nameMap = new HashMap<>();
 +          SERVICE_CONTRIBUTOR_MAP.put( contributor.getRole(), nameMap );
 +        }
 +        Map<Version, ServiceDeploymentContributor> versionMap = nameMap.get(contributor.getName());
 +        if (versionMap == null) {
 +          versionMap = new TreeMap<>();
 +          nameMap.put(contributor.getName(), versionMap);
 +        }
 +        versionMap.put( contributor.getVersion(), contributor );
 +      }
 +   }
 +
 +   private static void loadProviderContributors() {
 +    Set<ProviderDeploymentContributor> set = new HashSet<>();
 +    Map<String,Map<String,ProviderDeploymentContributor>> roleMap
 +        = new HashMap<>();
 +
 +    ServiceLoader<ProviderDeploymentContributor> loader = ServiceLoader.load( ProviderDeploymentContributor.class );
 +    Iterator<ProviderDeploymentContributor> contributors = loader.iterator();
 +    while( contributors.hasNext() ) {
 +      ProviderDeploymentContributor contributor = contributors.next();
 +      if( contributor.getName() == null ) {
 +        log.ignoringProviderContributorWithMissingName( contributor.getClass().getName() );
 +        continue;
 +      }
 +      if( contributor.getRole() == null ) {
 +        log.ignoringProviderContributorWithMissingRole( contributor.getClass().getName() );
 +        continue;
 +      }
 +      set.add( contributor );
 +      Map nameMap = roleMap.get( contributor.getRole() );
 +      if( nameMap == null ) {
 +        nameMap = new HashMap<>();
 +        roleMap.put( contributor.getRole(), nameMap );
 +      }
 +      nameMap.put( contributor.getName(), contributor );
 +    }
 +    PROVIDER_CONTRIBUTORS = set;
 +    PROVIDER_CONTRIBUTOR_MAP = roleMap;
 +  }
 +
 +  static ProviderDeploymentContributor getProviderContributor(
 +      Map<String,List<ProviderDeploymentContributor>> providers, String role, String name ) {
 +    ProviderDeploymentContributor contributor = null;
 +    if( name == null ) {
 +      List<ProviderDeploymentContributor> list = providers.get( role );
 +      if( list != null && !list.isEmpty() ) {
 +        contributor = list.get( 0 );
 +      }
 +    } else {
 +      contributor = getProviderContributor( role, name );
 +      // Explicit configuration that is wrong should just fail
 +      // rather than randomly select a provider. Implicit default
 +      // providers can be selected when no name is provided.
 +      if (contributor == null || !contributor.getRole().equals(role) ||
 +          !contributor.getName().equals(name)) {
 +        throw new DeploymentException(
 +            "Failed to contribute provider. Role: " +
 +            role + " Name: " + name + ". Please check the topology for" +
 +              	    " errors in name and role and that the provider is " +
 +              	    "on the classpath.");
 +      }
 +    }
 +    return contributor;
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ServiceDefinitionDeploymentContributor.java
----------------------------------------------------------------------
diff --cc gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ServiceDefinitionDeploymentContributor.java
index a056ac7,0000000..7e69af5
mode 100644,000000..100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ServiceDefinitionDeploymentContributor.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ServiceDefinitionDeploymentContributor.java
@@@ -1,256 -1,0 +1,264 @@@
 +/**
 + * 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 org.apache.knox.gateway.config.impl.GatewayConfigImpl;
 +import org.apache.knox.gateway.deploy.DeploymentContext;
 +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.dispatch.GatewayDispatchFilter;
 +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.service.definition.CustomDispatch;
 +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.Provider;
 +import org.apache.knox.gateway.topology.Service;
 +import org.apache.knox.gateway.topology.Version;
 +
 +import java.net.URISyntaxException;
 +import java.util.ArrayList;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +
 +public class ServiceDefinitionDeploymentContributor extends ServiceDeploymentContributorBase {
 +
 +  private static final String DISPATCH_ROLE = "dispatch";
 +
 +  private static final String DISPATCH_IMPL_PARAM = "dispatch-impl";
 +
 +  private static final String HTTP_CLIENT_FACTORY_PARAM = "httpClientFactory";
 +
 +  private static final String SERVICE_ROLE_PARAM = "serviceRole";
 +
 +  private static final String XFORWARDED_FILTER_NAME = "XForwardedHeaderFilter";
 +
 +  private static final String XFORWARDED_FILTER_ROLE = "xforwardedheaders";
 +
 +  private static final String DEFAULT_HA_DISPATCH_CLASS = "org.apache.knox.gateway.ha.dispatch.DefaultHaDispatch";
 +
 +  private static final String COOKIE_SCOPING_FILTER_NAME = "CookieScopeServletFilter";
 +
 +  private static final String COOKIE_SCOPING_FILTER_ROLE = "cookiescopef";
 +
 +  private ServiceDefinition serviceDefinition;
 +
 +  private UrlRewriteRulesDescriptor serviceRules;
 +
 +  public ServiceDefinitionDeploymentContributor(ServiceDefinition serviceDefinition, UrlRewriteRulesDescriptor serviceRules) {
 +    this.serviceDefinition = serviceDefinition;
 +    this.serviceRules = serviceRules;
 +  }
 +
 +  @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");
 +      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);
 +    }
 +    addDispatchFilter(context, service, resource, binding);
 +  }
 +
 +  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 ( "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);
 +  }
 +
 +  private void addDispatchFilter(DeploymentContext context, Service service, ResourceDescriptor resource, Route binding) {
 +    CustomDispatch customDispatch = binding.getDispatch();
 +    if ( customDispatch == null ) {
 +      customDispatch = serviceDefinition.getDispatch();
 +    }
 +    boolean isHaEnabled = isHaEnabled(context);
 +    if ( customDispatch != null ) {
 +      String haContributorName = customDispatch.getHaContributorName();
 +      String haClassName = customDispatch.getHaClassName();
 +      String httpClientFactory = customDispatch.getHttpClientFactory();
++      boolean useTwoWaySsl = customDispatch.getUseTwoWaySsl();
 +      if ( isHaEnabled) {
 +        if (haContributorName != null) {
 +          addDispatchFilter(context, service, resource, DISPATCH_ROLE, haContributorName);
 +        } else if (haClassName != null) {
-           addDispatchFilterForClass(context, service, resource, haClassName, httpClientFactory);
++          addDispatchFilterForClass(context, service, resource, haClassName, httpClientFactory, useTwoWaySsl);
 +        } else {
 +          addDefaultHaDispatchFilter(context, service, resource);
 +        }
 +      } else {
 +        String contributorName = customDispatch.getContributorName();
 +        if ( contributorName != null ) {
 +          addDispatchFilter(context, service, resource, DISPATCH_ROLE, contributorName);
 +        } else {
 +          String className = customDispatch.getClassName();
 +          if ( className != null ) {
-             addDispatchFilterForClass(context, service, resource, className, httpClientFactory);
++            addDispatchFilterForClass(context, service, resource, className, httpClientFactory, useTwoWaySsl);
 +          } else {
 +            //final fallback to the default dispatch
 +            addDispatchFilter(context, service, resource, DISPATCH_ROLE, "http-client");
 +          }
 +        }
 +      }
 +    } else if (isHaEnabled) {
 +      addDefaultHaDispatchFilter(context, service, resource);
 +    } else {
 +      addDispatchFilter(context, service, resource, DISPATCH_ROLE, "http-client");
 +    }
 +  }
 +
 +  private void addDefaultHaDispatchFilter(DeploymentContext context, Service service, ResourceDescriptor resource) {
 +    FilterDescriptor filter = addDispatchFilterForClass(context, service, resource, DEFAULT_HA_DISPATCH_CLASS, null);
 +    filter.param().name(SERVICE_ROLE_PARAM).value(service.getRole());
 +  }
 +
-   private FilterDescriptor addDispatchFilterForClass(DeploymentContext context, Service service, ResourceDescriptor resource, String dispatchClass, String httpClientFactory) {
++  private FilterDescriptor addDispatchFilterForClass(DeploymentContext context, Service service, ResourceDescriptor resource, String dispatchClass, String httpClientFactory, boolean useTwoWaySsl) {
 +    FilterDescriptor filter = resource.addFilter().name(getName()).role(DISPATCH_ROLE).impl(GatewayDispatchFilter.class);
 +    filter.param().name(DISPATCH_IMPL_PARAM).value(dispatchClass);
 +    if (httpClientFactory != null) {
 +      filter.param().name(HTTP_CLIENT_FACTORY_PARAM).value(httpClientFactory);
 +    }
++    // let's take the value of useTwoWaySsl which is derived from the service definition
++    // then allow it to be overridden by service params from the topology
++    filter.param().name("useTwoWaySsl").value(Boolean.toString(useTwoWaySsl));
 +    for ( Map.Entry<String, String> serviceParam : service.getParams().entrySet() ) {
 +      filter.param().name(serviceParam.getKey()).value(serviceParam.getValue());
 +    }
 +    if ( context.getGatewayConfig().isHadoopKerberosSecured() ) {
 +      filter.param().name("kerberos").value("true");
 +    } else {
 +      //TODO: [sumit] Get rid of special case. Add config/param capabilities to service definitions?
 +      //special case for hive
 +      filter.param().name("basicAuthPreemptive").value("true");
 +    }
 +    return filter;
 +  }
 +
++  private FilterDescriptor addDispatchFilterForClass(DeploymentContext context, Service service, ResourceDescriptor resource, String dispatchClass, String httpClientFactory) {
++    return addDispatchFilterForClass(context, service, resource, dispatchClass, httpClientFactory, false);
++  }
++
 +  private boolean isHaEnabled(DeploymentContext context) {
 +    Provider provider = getProviderByRole(context, "ha");
 +    if ( provider != null && provider.isEnabled() ) {
 +      Map<String, String> params = provider.getParams();
 +      if ( params != null ) {
 +        if ( params.containsKey(getRole()) ) {
 +          return true;
 +        }
 +      }
 +    }
 +    return false;
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-server/src/main/java/org/apache/knox/gateway/services/metrics/impl/instr/InstrHttpClientBuilderProvider.java
----------------------------------------------------------------------
diff --cc gateway-server/src/main/java/org/apache/knox/gateway/services/metrics/impl/instr/InstrHttpClientBuilderProvider.java
index 073adcd,0000000..1299d6f
mode 100644,000000..100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/metrics/impl/instr/InstrHttpClientBuilderProvider.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/metrics/impl/instr/InstrHttpClientBuilderProvider.java
@@@ -1,71 -1,0 +1,70 @@@
 +/**
 + * 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
 + * <p>
 + * http://www.apache.org/licenses/LICENSE-2.0
 + * <p>
 + * 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.services.metrics.impl.instr;
 +
 +import com.codahale.metrics.MetricRegistry;
 +import com.codahale.metrics.httpclient.HttpClientMetricNameStrategy;
 +import com.codahale.metrics.httpclient.InstrumentedHttpRequestExecutor;
 +import org.apache.knox.gateway.services.metrics.InstrumentationProvider;
 +import org.apache.knox.gateway.services.metrics.MetricsContext;
 +import org.apache.knox.gateway.services.metrics.impl.DefaultMetricsService;
 +import org.apache.http.Header;
 +import org.apache.http.HttpRequest;
 +import org.apache.http.RequestLine;
 +import org.apache.http.client.utils.URIBuilder;
 +import org.apache.http.impl.client.HttpClientBuilder;
 +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 +
 +import java.net.URISyntaxException;
 +
 +public class InstrHttpClientBuilderProvider implements
 +    InstrumentationProvider<HttpClientBuilder> {
 +
 +  @Override
 +  public HttpClientBuilder getInstrumented(MetricsContext metricsContext) {
 +    MetricRegistry registry = (MetricRegistry) metricsContext.getProperty(DefaultMetricsService.METRICS_REGISTRY);
-     return  HttpClientBuilder.create().setRequestExecutor(new InstrumentedHttpRequestExecutor(registry, TOPOLOGY_URL_AND_METHOD)).
-         setConnectionManager(new PoolingHttpClientConnectionManager());
++    return  HttpClientBuilder.create().setRequestExecutor(new InstrumentedHttpRequestExecutor(registry, TOPOLOGY_URL_AND_METHOD));
 +  }
 +
 +  @Override
 +  public HttpClientBuilder getInstrumented(HttpClientBuilder instanceClass, MetricsContext metricsContext) {
 +    throw new UnsupportedOperationException();
 +  }
 +
 +  private static final HttpClientMetricNameStrategy TOPOLOGY_URL_AND_METHOD = new HttpClientMetricNameStrategy() {
 +    public String getNameFor(String name, HttpRequest request) {
 +      try {
 +        String context = "";
 +        Header header = request.getFirstHeader("X-Forwarded-Context");
 +        if (header != null) {
 +          context = header.getValue();
 +        }
 +        RequestLine requestLine = request.getRequestLine();
 +        URIBuilder uriBuilder = new URIBuilder(requestLine.getUri());
 +        String resourcePath = InstrUtils.getResourcePath(uriBuilder.removeQuery().build().toString());
 +        return MetricRegistry.name("service", new String[]{name, context + resourcePath, methodNameString(request)});
 +      } catch (URISyntaxException e) {
 +        throw new IllegalArgumentException(e);
 +      }
 +    }
 +
 +    private String methodNameString(HttpRequest request) {
 +      return request.getRequestLine().getMethod().toLowerCase() + "-requests";
 +    }
 +  };
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-server/src/main/java/org/apache/knox/gateway/topology/builder/BeanPropertyTopologyBuilder.java
----------------------------------------------------------------------
diff --cc gateway-server/src/main/java/org/apache/knox/gateway/topology/builder/BeanPropertyTopologyBuilder.java
index a1a2609,0000000..afeade0
mode 100644,000000..100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/topology/builder/BeanPropertyTopologyBuilder.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/topology/builder/BeanPropertyTopologyBuilder.java
@@@ -1,105 -1,0 +1,116 @@@
 +/**
 + * 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.topology.builder;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +
 +import org.apache.knox.gateway.topology.Application;
 +import org.apache.knox.gateway.topology.Provider;
 +import org.apache.knox.gateway.topology.Service;
 +import org.apache.knox.gateway.topology.Topology;
 +
 +public class BeanPropertyTopologyBuilder implements TopologyBuilder {
 +
 +    private String name;
 +    private String defaultService;
++    private boolean isGenerated;
 +    private List<Provider> providers;
 +    private List<Service> services;
 +    private List<Application> applications;
 +
 +    public BeanPropertyTopologyBuilder() {
 +        providers = new ArrayList<Provider>();
 +        services = new ArrayList<Service>();
 +        applications = new ArrayList<Application>();
 +    }
 +
 +    public BeanPropertyTopologyBuilder name(String name) {
 +        this.name = name;
 +        return this;
 +    }
 +
 +    public String name() {
 +        return name;
 +    }
 +
++    public BeanPropertyTopologyBuilder generated(String isGenerated) {
++        this.isGenerated = Boolean.valueOf(isGenerated);
++        return this;
++    }
++
++    public boolean isGenerated() {
++        return isGenerated;
++    }
++
 +    public BeanPropertyTopologyBuilder defaultService(String defaultService) {
 +      this.defaultService = defaultService;
 +      return this;
 +    }
 +
 +    public String defaultService() {
 +      return defaultService;
 +    }
 +
 +    public BeanPropertyTopologyBuilder addProvider(Provider provider) {
 +        providers.add(provider);
 +        return this;
 +    }
 +
 +    public List<Provider> providers() {
 +        return providers;
 +    }
 +
 +    public BeanPropertyTopologyBuilder addService(Service service) {
 +        services.add(service);
 +        return this;
 +    }
 +
 +    public List<Service> services() {
 +        return services;
 +    }
 +
 +    public BeanPropertyTopologyBuilder addApplication( Application application ) {
 +        applications.add(application);
 +        return this;
 +    }
 +
 +    public List<Application> applications() {
 +        return applications;
 +    }
 +
 +    public Topology build() {
 +        Topology topology = new Topology();
 +        topology.setName(name);
 +        topology.setDefaultServicePath(defaultService);
++        topology.setGenerated(isGenerated);
 +
 +        for (Provider provider : providers) {
 +            topology.addProvider(provider);
 +        }
 +
 +        for (Service service : services) {
 +            topology.addService(service);
 +        }
 +
 +        for (Application application : applications) {
 +            topology.addApplication(application);
 +        }
 +
 +        return topology;
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptor.java
----------------------------------------------------------------------
diff --cc gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptor.java
index 25997b1,0000000..7d25286
mode 100644,000000..100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptor.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptor.java
@@@ -1,48 -1,0 +1,58 @@@
 +/**
 + * 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.topology.simple;
 +
 +import java.util.List;
 +import java.util.Map;
 +
 +public interface SimpleDescriptor {
 +
 +    String getName();
 +
 +    String getDiscoveryType();
 +
 +    String getDiscoveryAddress();
 +
 +    String getDiscoveryUser();
 +
 +    String getDiscoveryPasswordAlias();
 +
 +    String getClusterName();
 +
 +    String getProviderConfig();
 +
 +    List<Service> getServices();
 +
++    List<Application> getApplications();
++
 +
 +    interface Service {
 +        String getName();
 +
 +        Map<String, String> getParams();
 +
 +        List<String> getURLs();
 +    }
++
++    interface Application {
++        String getName();
++
++        Map<String, String> getParams();
++
++        List<String> getURLs();
++    }
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/2c69152f/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
----------------------------------------------------------------------
diff --cc gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
index b54432d,0000000..2e3214d
mode 100644,000000..100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
@@@ -1,267 -1,0 +1,316 @@@
 +/**
 + * 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.topology.simple;
 +
 +import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 +import org.apache.knox.gateway.services.Service;
 +import org.apache.knox.gateway.topology.discovery.DefaultServiceDiscoveryConfig;
 +import org.apache.knox.gateway.topology.discovery.ServiceDiscovery;
 +import org.apache.knox.gateway.topology.discovery.ServiceDiscoveryFactory;
 +import java.io.BufferedWriter;
 +import java.io.File;
 +import java.io.FileInputStream;
 +import java.io.FileWriter;
 +import java.io.InputStreamReader;
 +import java.io.IOException;
 +
 +import java.net.URI;
 +import java.net.URISyntaxException;
 +
 +import java.util.ArrayList;
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +
 +
 +
 +/**
 + * Processes simple topology descriptors, producing full topology files, which can subsequently be deployed to the
 + * gateway.
 + */
 +public class SimpleDescriptorHandler {
 +
 +    private static final Service[] NO_GATEWAY_SERVICES = new Service[]{};
 +
 +    private static final SimpleDescriptorMessages log = MessagesFactory.get(SimpleDescriptorMessages.class);
 +
 +    public static Map<String, File> handle(File desc) throws IOException {
 +        return handle(desc, NO_GATEWAY_SERVICES);
 +    }
 +
 +    public static Map<String, File> handle(File desc, Service...gatewayServices) throws IOException {
 +        return handle(desc, desc.getParentFile(), gatewayServices);
 +    }
 +
 +    public static Map<String, File> handle(File desc, File destDirectory) throws IOException {
 +        return handle(desc, destDirectory, NO_GATEWAY_SERVICES);
 +    }
 +
 +    public static Map<String, File> handle(File desc, File destDirectory, Service...gatewayServices) throws IOException {
 +        return handle(SimpleDescriptorFactory.parse(desc.getAbsolutePath()), desc.getParentFile(), destDirectory, gatewayServices);
 +    }
 +
 +    public static Map<String, File> handle(SimpleDescriptor desc, File srcDirectory, File destDirectory) {
 +        return handle(desc, srcDirectory, destDirectory, NO_GATEWAY_SERVICES);
 +    }
 +
 +    public static Map<String, File> handle(SimpleDescriptor desc, File srcDirectory, File destDirectory, Service...gatewayServices) {
 +        Map<String, File> result = new HashMap<>();
 +
 +        File topologyDescriptor;
 +
 +        DefaultServiceDiscoveryConfig sdc = new DefaultServiceDiscoveryConfig(desc.getDiscoveryAddress());
 +        sdc.setUser(desc.getDiscoveryUser());
 +        sdc.setPasswordAlias(desc.getDiscoveryPasswordAlias());
-         ServiceDiscovery sd = ServiceDiscoveryFactory.get(desc.getDiscoveryType(), gatewayServices);
++
++        // Use the discovery type from the descriptor. If it's unspecified, employ the default type.
++        String discoveryType = desc.getDiscoveryType();
++        if (discoveryType == null) {
++            discoveryType = "AMBARI";
++        }
++
++        ServiceDiscovery sd = ServiceDiscoveryFactory.get(discoveryType, gatewayServices);
 +        ServiceDiscovery.Cluster cluster = sd.discover(sdc, desc.getClusterName());
 +
 +        List<String> validServiceNames = new ArrayList<>();
 +
 +        Map<String, Map<String, String>> serviceParams = new HashMap<>();
 +        Map<String, List<String>>        serviceURLs   = new HashMap<>();
 +
 +        if (cluster != null) {
 +            for (SimpleDescriptor.Service descService : desc.getServices()) {
 +                String serviceName = descService.getName();
 +
 +                List<String> descServiceURLs = descService.getURLs();
 +                if (descServiceURLs == null || descServiceURLs.isEmpty()) {
 +                    descServiceURLs = cluster.getServiceURLs(serviceName);
 +                }
 +
 +                // Validate the discovered service URLs
 +                List<String> validURLs = new ArrayList<>();
 +                if (descServiceURLs != null && !descServiceURLs.isEmpty()) {
 +                    // Validate the URL(s)
 +                    for (String descServiceURL : descServiceURLs) {
 +                        if (validateURL(serviceName, descServiceURL)) {
 +                            validURLs.add(descServiceURL);
 +                        }
 +                    }
 +
 +                    if (!validURLs.isEmpty()) {
 +                        validServiceNames.add(serviceName);
 +                    }
 +                }
 +
 +                // If there is at least one valid URL associated with the service, then add it to the map
 +                if (!validURLs.isEmpty()) {
 +                    serviceURLs.put(serviceName, validURLs);
 +                } else {
 +                    log.failedToDiscoverClusterServiceURLs(serviceName, cluster.getName());
 +                }
 +
 +                // Service params
 +                if (descService.getParams() != null) {
 +                    serviceParams.put(serviceName, descService.getParams());
 +                    if (!validServiceNames.contains(serviceName)) {
 +                        validServiceNames.add(serviceName);
 +                    }
 +                }
 +            }
 +        } else {
 +            log.failedToDiscoverClusterServices(desc.getClusterName());
 +        }
 +
 +        BufferedWriter fw = null;
 +        topologyDescriptor = null;
 +        File providerConfig;
 +        try {
 +            // Verify that the referenced provider configuration exists before attempting to reading it
 +            providerConfig = resolveProviderConfigurationReference(desc.getProviderConfig(), srcDirectory);
 +            if (providerConfig == null) {
 +                log.failedToResolveProviderConfigRef(desc.getProviderConfig());
 +                throw new IllegalArgumentException("Unresolved provider configuration reference: " +
 +                                                   desc.getProviderConfig() + " ; Topology update aborted!");
 +            }
 +            result.put("reference", providerConfig);
 +
 +            // TODO: Should the contents of the provider config be validated before incorporating it into the topology?
 +
 +            String topologyFilename = desc.getName();
 +            if (topologyFilename == null) {
 +                topologyFilename = desc.getClusterName();
 +            }
 +            topologyDescriptor = new File(destDirectory, topologyFilename + ".xml");
++
 +            fw = new BufferedWriter(new FileWriter(topologyDescriptor));
 +
++            fw.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
++
++            fw.write("<!--==============================================-->\n");
++            fw.write("<!-- DO NOT EDIT. This is an auto-generated file. -->\n");
++            fw.write("<!--==============================================-->\n");
++
 +            fw.write("<topology>\n");
 +
++            // KNOX-1105 Indicate that this topology was auto-generated
++            fw.write("    <generated>true</generated>\n");
++
 +            // Copy the externalized provider configuration content into the topology descriptor in-line
 +            InputStreamReader policyReader = new InputStreamReader(new FileInputStream(providerConfig));
 +            char[] buffer = new char[1024];
 +            int count;
 +            while ((count = policyReader.read(buffer)) > 0) {
 +                fw.write(buffer, 0, count);
 +            }
 +            policyReader.close();
 +
++            // Services
 +            // Sort the service names to write the services alphabetically
 +            List<String> serviceNames = new ArrayList<>(validServiceNames);
 +            Collections.sort(serviceNames);
 +
 +            // Write the service declarations
 +            for (String serviceName : serviceNames) {
 +                fw.write("    <service>\n");
 +                fw.write("        <role>" + serviceName + "</role>\n");
 +
 +                // URLs
 +                List<String> urls = serviceURLs.get(serviceName);
 +                if (urls != null) {
 +                    for (String url : urls) {
 +                        fw.write("        <url>" + url + "</url>\n");
 +                    }
 +                }
 +
 +                // Params
 +                Map<String, String> svcParams = serviceParams.get(serviceName);
 +                if (svcParams != null) {
 +                    for (String paramName : svcParams.keySet()) {
 +                        fw.write("        <param>\n");
 +                        fw.write("            <name>" + paramName + "</name>\n");
 +                        fw.write("            <value>" + svcParams.get(paramName) + "</value>\n");
 +                        fw.write("        </param>\n");
 +                    }
 +                }
 +
 +                fw.write("    </service>\n");
 +            }
 +
++            // Applications
++            List<SimpleDescriptor.Application> apps = desc.getApplications();
++            if (apps != null) {
++                for (SimpleDescriptor.Application app : apps) {
++                    fw.write("    <application>\n");
++                    fw.write("        <name>" + app.getName() + "</name>\n");
++
++                    // URLs
++                    List<String> urls = app.getURLs();
++                    if (urls != null) {
++                        for (String url : urls) {
++                            fw.write("        <url>" + url + "</url>\n");
++                        }
++                    }
++
++                    // Params
++                    Map<String, String> appParams = app.getParams();
++                    if (appParams != null) {
++                        for (String paramName : appParams.keySet()) {
++                            fw.write("        <param>\n");
++                            fw.write("            <name>" + paramName + "</name>\n");
++                            fw.write("            <value>" + appParams.get(paramName) + "</value>\n");
++                            fw.write("        </param>\n");
++                        }
++                    }
++
++                    fw.write("    </application>\n");
++                }
++            }
++
 +            fw.write("</topology>\n");
 +
 +            fw.flush();
 +        } catch (IOException e) {
 +            log.failedToGenerateTopologyFromSimpleDescriptor(topologyDescriptor.getName(), e);
 +            topologyDescriptor.delete();
 +        } finally {
 +            if (fw != null) {
 +                try {
 +                    fw.close();
 +                } catch (IOException e) {
 +                    // ignore
 +                }
 +            }
 +        }
 +
 +        result.put("topology", topologyDescriptor);
 +        return result;
 +    }
 +
++
 +    private static boolean validateURL(String serviceName, String url) {
 +        boolean result = false;
 +
 +        if (url != null && !url.isEmpty()) {
 +            try {
 +                new URI(url);
 +                result = true;
 +            } catch (URISyntaxException e) {
 +                log.serviceURLValidationFailed(serviceName, url, e);
 +            }
 +        }
 +
 +        return result;
 +    }
 +
 +
 +    private static File resolveProviderConfigurationReference(String reference, File srcDirectory) {
 +        File providerConfig;
 +
 +        // If the reference includes a path
 +        if (reference.contains(File.separator)) {
 +            // Check if it's an absolute path
 +            providerConfig = new File(reference);
 +            if (!providerConfig.exists()) {
 +                // If it's not an absolute path, try treating it as a relative path
 +                providerConfig = new File(srcDirectory, reference);
 +                if (!providerConfig.exists()) {
 +                    providerConfig = null;
 +                }
 +            }
 +        } else { // No file path, just a name
 +            // Check if it's co-located with the referencing descriptor
 +            providerConfig = new File(srcDirectory, reference);
 +            if (!providerConfig.exists()) {
 +                // Check the shared-providers config location
 +                File sharedProvidersDir = new File(srcDirectory, "../shared-providers");
 +                if (sharedProvidersDir.exists()) {
 +                    providerConfig = new File(sharedProvidersDir, reference);
 +                    if (!providerConfig.exists()) {
 +                        // Check if it's a valid name without the extension
 +                        providerConfig = new File(sharedProvidersDir, reference + ".xml");
 +                        if (!providerConfig.exists()) {
 +                            providerConfig = null;
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +
 +        return providerConfig;
 +    }
 +
 +}