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;
+ }
+
+}