You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by km...@apache.org on 2016/02/25 21:54:24 UTC

[4/5] knox git commit: [KNOX-670] - Knox should be able to sost simple web apps

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/DeploymentFactory.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/DeploymentFactory.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/DeploymentFactory.java
index fd28b8e..4815595 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/DeploymentFactory.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/DeploymentFactory.java
@@ -17,49 +17,56 @@
  */
 package org.apache.hadoop.gateway.deploy;
 
-import org.apache.hadoop.gateway.GatewayForwardingServlet;
+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.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.hadoop.gateway.GatewayMessages;
 import org.apache.hadoop.gateway.GatewayServlet;
 import org.apache.hadoop.gateway.config.GatewayConfig;
+import org.apache.hadoop.gateway.deploy.impl.ApplicationDeploymentContributor;
 import org.apache.hadoop.gateway.descriptor.GatewayDescriptor;
 import org.apache.hadoop.gateway.descriptor.GatewayDescriptorFactory;
 import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
 import org.apache.hadoop.gateway.services.GatewayServices;
 import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
+import org.apache.hadoop.gateway.topology.Application;
 import org.apache.hadoop.gateway.topology.Provider;
 import org.apache.hadoop.gateway.topology.Service;
+import org.apache.hadoop.gateway.topology.Service;
 import org.apache.hadoop.gateway.topology.Topology;
 import org.apache.hadoop.gateway.topology.Version;
 import org.apache.hadoop.gateway.util.ServiceDefinitionsLoader;
+import org.apache.hadoop.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;
 
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
-import java.beans.Statement;
-import java.io.File;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.ArrayList;
-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.ServiceLoader;
-import java.util.Set;
-import java.util.TreeMap;
-
 public abstract class DeploymentFactory {
 
-  private static final String DEFAULT_APP_REDIRECT_CONTEXT_PATH = "redirectTo";
+  private static final String SERVLET_NAME_SUFFIX = "-knox-gateway-servlet";
+  private static final String FILTER_NAME_SUFFIX = "-knox-gateway-filter";
   private static GatewayMessages log = MessagesFactory.get( GatewayMessages.class );
   private static GatewayServices gatewayServices = null;
 
@@ -78,30 +85,120 @@ public abstract class DeploymentFactory {
     DeploymentFactory.gatewayServices = services;
   }
 
-  public static WebArchive createDeployment( GatewayConfig config, Topology topology ) {
-    DeploymentContext context = null;
-     //TODO move the loading of service defs
-    String stacks = config.getGatewayServicesDir();
-    log.usingServicesDirectory(stacks);
-    File stacksDir = new File(stacks);
-    Set<ServiceDeploymentContributor> deploymentContributors = ServiceDefinitionsLoader.loadServiceDefinitions(stacksDir);
-    addServiceDeploymentContributors(deploymentContributors.iterator());
+  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 );
-    context = createDeploymentContext( config, topology.getName(), topology, providers, services );
-    initialize( context, providers, services );
-    contribute( context, providers, services );
-    finalize( context, providers, services );
-    if (topology.getName().equals("_default")) {
-      // if this is the default topology then add the forwarding webapp as well
-      context = deployDefaultTopology(config, 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 );
     }
-    storeTopology( context, topology );
+    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();
   }
 
-  private static void storeTopology( DeploymentContext context, Topology topology ) {
+  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 {
@@ -120,41 +217,20 @@ public abstract class DeploymentFactory {
       throw new DeploymentException( "Failed to marshall topology.", e );
     }
     StringAsset asset = new StringAsset( xml );
-    context.getWebArchive().addAsWebInfResource( asset, "topology.xml" );
-  }
-
-  private static DeploymentContext deployDefaultTopology(GatewayConfig config,
-      Topology topology) {
-    // this is the "default" topology which does some specialized
-    // redirects for compatibility with hadoop cli java client use
-    // we do not want the various listeners and providers added or
-    // the usual gateway.xml, etc.
-    DeploymentContext context;
-    Map<String,List<ProviderDeploymentContributor>> providers = new HashMap<String,List<ProviderDeploymentContributor>>();
-    Map<String,List<ServiceDeploymentContributor>> services = new HashMap<String,List<ServiceDeploymentContributor>>();
-    context = createDeploymentContext( config, "forward", topology, providers, services);
-    WebAppDescriptor wad = context.getWebAppDescriptor();
-    String servletName = context.getTopology().getName();
-    String servletClass = GatewayForwardingServlet.class.getName();
-    wad.createServlet().servletName( servletName ).servletClass( servletClass );
-    wad.createServletMapping().servletName( servletName ).urlPattern( "/*" );
-    ServletType<WebAppDescriptor> servlet = findServlet( context, context.getTopology().getName() );
-    servlet.createInitParam()
-      .paramName( DEFAULT_APP_REDIRECT_CONTEXT_PATH )
-      .paramValue( config.getDefaultAppRedirectPath() );
-    writeDeploymentDescriptor(context);
-    return context;
+    return asset;
   }
 
   private static DeploymentContext createDeploymentContext(
-      GatewayConfig config, String archiveName, Topology topology,
-      Map<String,List<ProviderDeploymentContributor>> providers,
-      Map<String,List<ServiceDeploymentContributor>> services ) {
-    WebArchive webArchive = ShrinkWrap.create( WebArchive.class, archiveName );
+      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, services );
+        config, topology, gateway, webArchive, webAppDesc, providers );
     return context;
   }
 
@@ -235,41 +311,108 @@ public abstract class DeploymentFactory {
     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<String,List<ServiceDeploymentContributor>> services,
+      Map.Entry<String,ServiceDeploymentContributor> applications ) {
     WebAppDescriptor wad = context.getWebAppDescriptor();
-    String servletName = context.getTopology().getName();
-    String servletClass = GatewayServlet.class.getName();
-    wad.createServlet().servletName( servletName ).servletClass( servletClass );
-    wad.createServletMapping().servletName( servletName ).urlPattern( "/*" );
+    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();
     }
-    for( String role : providers.keySet() ) {
-      for( ProviderDeploymentContributor contributor : providers.get( role ) ) {
-        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);
+    initializeProviders( context, providers );
+    initializeServices( context, services );
+    initializeApplications( context, applications );
+  }
+
+  private static void initializeProviders(
+      DeploymentContext context,
+      Map<String,List<ProviderDeploymentContributor>> providers ) {
+    if( providers != null ) {
+      for( String role : providers.keySet() ) {
+        for( ProviderDeploymentContributor contributor : providers.get( role ) ) {
+          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 );
+          }
         }
       }
     }
-    for( String role : services.keySet() ) {
-      for( ServiceDeploymentContributor contributor : services.get( role ) ) {
+  }
+
+  private static void initializeServices( DeploymentContext context, Map<String, List<ServiceDeploymentContributor>> services ) {
+    if( services != null ) {
+      for( String role : services.keySet() ) {
+        for( ServiceDeploymentContributor contributor : services.get( role ) ) {
+          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.initializeService( contributor.getName(), contributor.getRole() );
+          injectServices( contributor );
+          log.initializeApplication( contributor.getName() );
           contributor.initializeContribution( context );
         } catch( Exception e ) {
           log.failedToInitializeContribution( e );
-          throw new DeploymentException("Failed to initialize contribution.", e);
+          throw new DeploymentException( "Failed to initialize application contribution.", e );
         }
       }
     }
@@ -300,8 +443,15 @@ public abstract class DeploymentFactory {
   private static void contribute(
       DeploymentContext context,
       Map<String,List<ProviderDeploymentContributor>> providers,
-      Map<String,List<ServiceDeploymentContributor>> services ) {
-      Topology topology = context.getTopology();
+      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() ) {
@@ -315,23 +465,44 @@ public abstract class DeploymentFactory {
         }
       }
     }
-    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() );
+  }
+
+  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 ) {
-          // Maybe it makes sense to throw exception
-          log.failedToContributeService( service.getName(), service.getRole(), e );
-          throw new DeploymentException("Failed to contribute service.", e);
+          log.failedToInitializeContribution( e );
+          throw new DeploymentException( "Failed to contribution application.", e );
         }
       }
     }
@@ -374,7 +545,8 @@ public abstract class DeploymentFactory {
   private static void finalize(
       DeploymentContext context,
       Map<String,List<ProviderDeploymentContributor>> providers,
-      Map<String,List<ServiceDeploymentContributor>> services ) {
+      Map<String,List<ServiceDeploymentContributor>> services,
+      Map.Entry<String,ServiceDeploymentContributor> application ) {
     try {
       // Write the gateway descriptor (gateway.xml) into the war.
       StringWriter writer = new StringWriter();
@@ -384,14 +556,33 @@ public abstract class DeploymentFactory {
           GatewayServlet.GATEWAY_DESCRIPTOR_LOCATION_DEFAULT );
 
       // Set the location of the gateway descriptor as a servlet init param.
-      ServletType<WebAppDescriptor> servlet = findServlet( context, context.getTopology().getName() );
-      servlet.createInitParam()
-          .paramName( GatewayServlet.GATEWAY_DESCRIPTOR_LOCATION_PARAM )
-          .paramValue( GatewayServlet.GATEWAY_DESCRIPTOR_LOCATION_DEFAULT );
-
+      if( application == null ) {
+        String servletName = context.getTopology().getName() + SERVLET_NAME_SUFFIX;
+        ServletType<WebAppDescriptor> servlet = findServlet( context, servletName );
+        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 );
+        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( String role : providers.keySet() ) {
         for( ProviderDeploymentContributor contributor : providers.get( role ) ) {
           try {
@@ -400,10 +591,15 @@ public abstract class DeploymentFactory {
           } catch( Exception e ) {
             // Maybe it makes sense to throw exception
             log.failedToFinalizeContribution( e );
-            throw new DeploymentException("Failed to finalize contribution.", e);
+            throw new DeploymentException( "Failed to finalize contribution.", e );
           }
         }
       }
+    }
+  }
+
+  private static void finalizeServices( DeploymentContext context, Map<String, List<ServiceDeploymentContributor>> services ) {
+    if( services != null ) {
       for( String role : services.keySet() ) {
         for( ServiceDeploymentContributor contributor : services.get( role ) ) {
           try {
@@ -412,22 +608,36 @@ public abstract class DeploymentFactory {
           } catch( Exception e ) {
             // Maybe it makes sense to throw exception
             log.failedToFinalizeContribution( e );
-            throw new DeploymentException("Failed to finalize contribution.", e);
+            throw new DeploymentException( "Failed to finalize contribution.", e );
           }
         }
       }
+    }
+  }
 
-      writeDeploymentDescriptor(context);
-
-    } catch ( IOException e ) {
-      throw new RuntimeException( 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) {
+  private static void writeDeploymentDescriptor( DeploymentContext context, boolean override ) {
     // Write the web.xml into the war.
     Asset webXmlAsset = new StringAsset( context.getWebAppDescriptor().exportAsString() );
-    context.getWebArchive().setWebXML( webXmlAsset );
+    if( override ) {
+      context.getWebArchive().addAsWebInfResource( webXmlAsset, "override-web.xml" );
+    } else {
+      context.getWebArchive().setWebXML( webXmlAsset );
+    }
   }
 
   public static ServletType<WebAppDescriptor> findServlet( DeploymentContext context, String name ) {
@@ -440,6 +650,24 @@ public abstract class DeploymentFactory {
     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<String, Map<String, Map<Version, ServiceDeploymentContributor>>>();
     ServiceLoader<ServiceDeploymentContributor> loader = ServiceLoader.load( ServiceDeploymentContributor.class );

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/ApplicationDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/ApplicationDeploymentContributor.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/ApplicationDeploymentContributor.java
new file mode 100644
index 0000000..3f68ede
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/ApplicationDeploymentContributor.java
@@ -0,0 +1,214 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.deploy.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.hadoop.gateway.config.GatewayConfig;
+import org.apache.hadoop.gateway.deploy.DeploymentContext;
+import org.apache.hadoop.gateway.deploy.DeploymentException;
+import org.apache.hadoop.gateway.deploy.ServiceDeploymentContributorBase;
+import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
+import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
+import org.apache.hadoop.gateway.filter.XForwardedHeaderFilter;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteRulesDescriptorFactory;
+import org.apache.hadoop.gateway.service.definition.Policy;
+import org.apache.hadoop.gateway.service.definition.Rewrite;
+import org.apache.hadoop.gateway.service.definition.Route;
+import org.apache.hadoop.gateway.service.definition.ServiceDefinition;
+import org.apache.hadoop.gateway.topology.Application;
+import org.apache.hadoop.gateway.topology.Service;
+import org.apache.hadoop.gateway.topology.Version;
+
+public class ApplicationDeploymentContributor extends ServiceDeploymentContributorBase {
+
+  private static final String SERVICE_DEFINITION_FILE_NAME = "service.xml";
+  private static final String REWRITE_RULES_FILE_NAME = "rewrite.xml";
+  private static final String XFORWARDED_FILTER_NAME = "XForwardedHeaderFilter";
+  private static final String XFORWARDED_FILTER_ROLE = "xforwardedheaders";
+
+  private ServiceDefinition serviceDefinition;
+
+  private UrlRewriteRulesDescriptor serviceRules;
+
+  private static ServiceDefinition loadServiceDefinition( Application application, File file ) throws JAXBException, FileNotFoundException {
+    ServiceDefinition definition;
+    if( !file.exists() ) {
+      definition = new ServiceDefinition();
+      definition.setName( application.getName() );
+      List<Route> routes = new ArrayList<Route>(1);
+      Route route;
+      route = new Route();
+      route.setPath( "/?**" );
+      routes.add( route );
+      route = new Route();
+      route.setPath( "/**?**" );
+      routes.add( route );
+      definition.setRoutes( routes );
+    } else {
+      JAXBContext context = JAXBContext.newInstance( ServiceDefinition.class );
+      Unmarshaller unmarshaller = context.createUnmarshaller();
+      FileInputStream inputStream = new FileInputStream( file );
+      definition = (ServiceDefinition) unmarshaller.unmarshal( inputStream );
+    }
+    return definition;
+  }
+
+  private static UrlRewriteRulesDescriptor loadRewriteRules( Application application, File file ) throws IOException {
+    UrlRewriteRulesDescriptor rules;
+    if( !file.exists() ) {
+      rules = UrlRewriteRulesDescriptorFactory.load( "xml", new StringReader( "<rules/>" ) );
+    } else {
+      FileReader reader = new FileReader( file );
+      rules = UrlRewriteRulesDescriptorFactory.load( "xml", reader );
+      reader.close();
+    }
+    return rules;
+  }
+
+  public ApplicationDeploymentContributor( GatewayConfig config, Application application ) throws DeploymentException {
+    try {
+      File appsDir = new File( config.getGatewayApplicationsDir() );
+      File appDir = new File( appsDir, application.getName() );
+      File serviceFile = new File( appDir, SERVICE_DEFINITION_FILE_NAME );
+      File rewriteFile = new File( appDir, REWRITE_RULES_FILE_NAME );
+      serviceDefinition = loadServiceDefinition( application, serviceFile );
+      serviceRules = loadRewriteRules( application, rewriteFile );
+    } catch ( IOException e ) {
+      throw new DeploymentException( "Failed to deploy application: " + application.getName(), e );
+    } catch ( JAXBException e ){
+      throw new DeploymentException( "Failed to deploy application: " + application.getName(), e );
+    }
+  }
+
+  @Override
+  public String getRole() {
+    return serviceDefinition.getRole();
+  }
+
+  @Override
+  public String getName() {
+    return serviceDefinition.getName();
+  }
+
+  @Override
+  public Version getVersion() {
+    return new Version(serviceDefinition.getVersion());
+  }
+
+  @Override
+  public void contributeService(DeploymentContext context, Service service) throws Exception {
+    contributeRewriteRules(context, service);
+    contributeResources(context, service);
+  }
+
+  private void contributeRewriteRules(DeploymentContext context, Service service) {
+    if ( serviceRules != null ) {
+      UrlRewriteRulesDescriptor clusterRules = context.getDescriptor("rewrite");
+      clusterRules.addRules(serviceRules);
+    }
+  }
+
+  private void contributeResources(DeploymentContext context, Service service) {
+    Map<String, String> filterParams = new HashMap<String, String>();
+    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);
+    }
+    List<Policy> policyBindings = binding.getPolicies();
+    if ( policyBindings == null ) {
+      policyBindings = serviceDefinition.getPolicies();
+    }
+    if ( policyBindings == null ) {
+      //add default set
+      addDefaultPolicies(context, service, filterParams, params, resource);
+    } else {
+      addPolicies(context, service, filterParams, params, resource, policyBindings);
+    }
+  }
+
+  private void addPolicies( DeploymentContext context, Service service, Map<String, String> filterParams, List<FilterParamDescriptor> params, ResourceDescriptor resource, List<Policy> policyBindings) throws URISyntaxException {
+    for ( Policy policyBinding : policyBindings ) {
+      String role = policyBinding.getRole();
+      if ( role == null ) {
+        throw new IllegalArgumentException("Policy defined has no role for service " + service.getName());
+      }
+      role = role.trim().toLowerCase();
+      if ( role.equals("rewrite") ) {
+        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);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/main/java/org/apache/hadoop/gateway/descriptor/xml/XmlGatewayDescriptorExporter.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/descriptor/xml/XmlGatewayDescriptorExporter.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/descriptor/xml/XmlGatewayDescriptorExporter.java
index d9151a3..207fd54 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/descriptor/xml/XmlGatewayDescriptorExporter.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/descriptor/xml/XmlGatewayDescriptorExporter.java
@@ -17,26 +17,20 @@
  */
 package org.apache.hadoop.gateway.descriptor.xml;
 
+import java.io.IOException;
+import java.io.Writer;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
 import org.apache.hadoop.gateway.descriptor.FilterDescriptor;
 import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
 import org.apache.hadoop.gateway.descriptor.GatewayDescriptor;
 import org.apache.hadoop.gateway.descriptor.GatewayDescriptorExporter;
 import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
+import org.apache.hadoop.gateway.util.XmlUtils;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import java.io.IOException;
-import java.io.Writer;
-
 public class XmlGatewayDescriptorExporter implements GatewayDescriptorExporter, XmlGatewayDescriptorTags {
 
   @Override
@@ -47,10 +41,7 @@ public class XmlGatewayDescriptorExporter implements GatewayDescriptorExporter,
   @Override
   public void store( GatewayDescriptor descriptor, Writer writer ) throws IOException {
     try {
-      DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
-      DocumentBuilder builder = builderFactory.newDocumentBuilder();
-      Document document = builder.newDocument();
-      document.setXmlStandalone( true );
+      Document document = XmlUtils.createDocument();
 
       Element gateway = document.createElement( GATEWAY );
       document.appendChild( gateway );
@@ -59,16 +50,7 @@ public class XmlGatewayDescriptorExporter implements GatewayDescriptorExporter,
         gateway.appendChild( createResource( document, resource ) );
       }
 
-      TransformerFactory transformerFactory = TransformerFactory.newInstance();
-      transformerFactory.setAttribute( "indent-number", 2 );
-      Transformer transformer = transformerFactory.newTransformer();
-      //transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "yes" );
-      transformer.setOutputProperty( OutputKeys.STANDALONE, "yes" );
-      transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
-
-      StreamResult result = new StreamResult( writer );
-      DOMSource source = new DOMSource(document);
-      transformer.transform( source, result );
+      XmlUtils.writeXml( document, writer );
 
     } catch( ParserConfigurationException e ) {
       throw new IOException( e );

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/DefaultTopologyHandler.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/DefaultTopologyHandler.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/DefaultTopologyHandler.java
new file mode 100644
index 0000000..75a2aed
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/DefaultTopologyHandler.java
@@ -0,0 +1,104 @@
+/**
+ * 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.hadoop.gateway.filter;
+
+import java.io.IOException;
+import java.util.Collection;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.hadoop.gateway.GatewayMessages;
+import org.apache.hadoop.gateway.config.GatewayConfig;
+import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.topology.TopologyService;
+import org.apache.hadoop.gateway.topology.Topology;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
+
+public class DefaultTopologyHandler extends HandlerWrapper {
+
+  private static GatewayMessages LOG = MessagesFactory.get(GatewayMessages.class);
+
+  private GatewayConfig config;
+  private GatewayServices services;
+  private String staticRedirectContext = null;
+
+  public DefaultTopologyHandler( GatewayConfig config, GatewayServices services, Handler delegate ) {
+    if( config == null ) {
+      throw new IllegalArgumentException( "config==null" );
+    }
+    if( services == null ) {
+      throw new IllegalArgumentException( "services==null" );
+    }
+    this.config = config;
+    this.services = services;
+    String defaultTopologyName = config.getDefaultTopologyName();
+    if( defaultTopologyName != null ) {
+      staticRedirectContext = config.getDefaultAppRedirectPath();
+      if( staticRedirectContext != null && staticRedirectContext.trim().isEmpty() ) {
+        staticRedirectContext = null;
+      }
+    }
+    if( staticRedirectContext != null ) {
+      LOG.defaultTopologySetup( defaultTopologyName, staticRedirectContext );
+    }
+    setHandler( delegate );
+  }
+
+  @Override
+  public void handle( String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException {
+    if( !baseRequest.isHandled() ) {
+      String redirectContext = staticRedirectContext;
+      if( redirectContext == null ) {
+        TopologyService topologies = services.getService( GatewayServices.TOPOLOGY_SERVICE );
+        if( topologies != null ) {
+          Collection<Topology> candidates = topologies.getTopologies();
+          if( candidates != null && candidates.size() == 1 ) {
+            Topology topology = candidates.iterator().next();
+            redirectContext = "/" + config.getGatewayPath() + "/" + topology.getName();
+          }
+        }
+      }
+      if( redirectContext != null ) {
+        String newTarget = redirectContext + target;
+        ForwardedRequest newRequest = new ForwardedRequest( request, newTarget );
+        LOG.defaultTopologyForward( target, newTarget );
+        super.handle( newTarget, baseRequest, newRequest, response );
+      }
+    }
+  }
+
+  private static class ForwardedRequest extends HttpServletRequestWrapper {
+
+    private String contextPath;
+
+    public ForwardedRequest( HttpServletRequest request, String contextPath ) {
+      super( request );
+      this.contextPath = contextPath;
+    }
+
+    public String getContextPath() {
+      return contextPath;
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/GatewayHelloFilter.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/GatewayHelloFilter.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/GatewayHelloFilter.java
new file mode 100644
index 0000000..ab56a34
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/filter/GatewayHelloFilter.java
@@ -0,0 +1,45 @@
+/**
+ * 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.hadoop.gateway.filter;
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+public class GatewayHelloFilter implements Filter {
+
+  @Override
+  public void init( FilterConfig filterConfig ) throws ServletException {
+    System.out.println( "GatewayHelloFilter.init" );
+  }
+
+  @Override
+  public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException {
+    System.out.println( "GatewayHelloFilter.doFilter" );
+    chain.doFilter( request, response );
+  }
+
+  @Override
+  public void destroy() {
+    System.out.println( "GatewayHelloFilter.destroy" );
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/builder/BeanPropertyTopologyBuilder.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/builder/BeanPropertyTopologyBuilder.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/builder/BeanPropertyTopologyBuilder.java
index 90f7f79..b5e80d2 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/builder/BeanPropertyTopologyBuilder.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/builder/BeanPropertyTopologyBuilder.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.gateway.topology.builder;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.hadoop.gateway.topology.Application;
 import org.apache.hadoop.gateway.topology.Provider;
 import org.apache.hadoop.gateway.topology.Service;
 import org.apache.hadoop.gateway.topology.Topology;
@@ -28,10 +29,12 @@ public class BeanPropertyTopologyBuilder implements TopologyBuilder {
     private String name;
     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) {
@@ -61,6 +64,15 @@ public class BeanPropertyTopologyBuilder implements TopologyBuilder {
         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);
@@ -73,6 +85,10 @@ public class BeanPropertyTopologyBuilder implements TopologyBuilder {
             topology.addService(service);
         }
 
+        for (Application application : applications) {
+            topology.addApplication(application);
+        }
+
         return topology;
     }
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/validation/TopologyValidator.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/validation/TopologyValidator.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/validation/TopologyValidator.java
index e15282b..37d202f 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/validation/TopologyValidator.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/validation/TopologyValidator.java
@@ -18,23 +18,22 @@
 
 package org.apache.hadoop.gateway.topology.validation;
 
-import org.apache.hadoop.gateway.config.GatewayConfig;
-import org.apache.hadoop.gateway.topology.Topology;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-
-import javax.xml.XMLConstants;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
-import javax.xml.validation.Validator;
 import java.io.File;
 import java.io.IOException;
 import java.net.URL;
 import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
+import javax.xml.XMLConstants;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+
+import org.apache.hadoop.gateway.topology.Topology;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
 
 public class TopologyValidator {
 
@@ -56,11 +55,10 @@ public class TopologyValidator {
   public boolean validateTopology() {
     errors = new LinkedList<String>();
     try {
-      File xml = new File(filePath);
-
       SchemaFactory fact = SchemaFactory
           .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-      Schema s = fact.newSchema( this.getClass().getClassLoader().getResource( "conf/topology-v1.xsd" ) );
+      URL schemaUrl = ClassLoader.getSystemResource( "conf/topology-v1.xsd" );
+      Schema s = fact.newSchema( schemaUrl );
       Validator validator = s.newValidator();
       final List<SAXParseException> exceptions = new LinkedList<>();
       validator.setErrorHandler(new ErrorHandler() {
@@ -77,6 +75,7 @@ public class TopologyValidator {
         }
       });
 
+      File xml = new File(filePath);
       validator.validate(new StreamSource(xml));
       if(exceptions.size() > 0) {
         for (SAXParseException e : exceptions) {

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/xml/KnoxFormatXmlTopologyRules.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/xml/KnoxFormatXmlTopologyRules.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/xml/KnoxFormatXmlTopologyRules.java
index b32f0c9..e573d63 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/xml/KnoxFormatXmlTopologyRules.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/xml/KnoxFormatXmlTopologyRules.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.gateway.topology.xml;
 
 import org.apache.commons.digester3.Rule;
 import org.apache.commons.digester3.binder.AbstractRulesModule;
+import org.apache.hadoop.gateway.topology.Application;
 import org.apache.hadoop.gateway.topology.Param;
 import org.apache.hadoop.gateway.topology.Provider;
 import org.apache.hadoop.gateway.topology.Service;
@@ -31,6 +32,7 @@ public class KnoxFormatXmlTopologyRules extends AbstractRulesModule {
   private static final String ROOT_TAG = "topology";
   private static final String NAME_TAG = "name";
   private static final String VERSION_TAG = "version";
+  private static final String APPLICATION_TAG = "application";
   private static final String SERVICE_TAG = "service";
   private static final String ROLE_TAG = "role";
   private static final String URL_TAG = "url";
@@ -47,6 +49,15 @@ public class KnoxFormatXmlTopologyRules extends AbstractRulesModule {
     forPattern( ROOT_TAG + "/" + NAME_TAG ).callMethod("name").usingElementBodyAsArgument();
     forPattern( ROOT_TAG + "/" + VERSION_TAG ).callMethod("version").usingElementBodyAsArgument();
 
+    forPattern( ROOT_TAG + "/" + APPLICATION_TAG ).createObject().ofType( Application.class ).then().setNext( "addApplication" );
+    forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + ROLE_TAG ).setBeanProperty();
+    forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + NAME_TAG ).setBeanProperty();
+    forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + VERSION_TAG ).createObject().ofType(Version.class).then().setBeanProperty().then().setNext("setVersion");
+    forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + URL_TAG ).callMethod( "addUrl" ).usingElementBodyAsArgument();
+    forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + PARAM_TAG ).createObject().ofType( Param.class ).then().addRule( paramRule ).then().setNext( "addParam" );
+    forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + PARAM_TAG + "/" + NAME_TAG ).setBeanProperty();
+    forPattern( ROOT_TAG + "/" + APPLICATION_TAG + "/" + PARAM_TAG + "/" + VALUE_TAG ).setBeanProperty();
+
     forPattern( ROOT_TAG + "/" + SERVICE_TAG ).createObject().ofType( Service.class ).then().setNext( "addService" );
     forPattern( ROOT_TAG + "/" + SERVICE_TAG + "/" + ROLE_TAG ).setBeanProperty();
     forPattern( ROOT_TAG + "/" + SERVICE_TAG + "/" + NAME_TAG ).setBeanProperty();

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/main/java/org/apache/hadoop/gateway/util/KnoxCLI.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/util/KnoxCLI.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/util/KnoxCLI.java
index 780f944..c865bfb 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/util/KnoxCLI.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/util/KnoxCLI.java
@@ -17,6 +17,25 @@
  */
 package org.apache.hadoop.gateway.util;
 
+import java.io.BufferedReader;
+import java.io.Console;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.UUID;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.FileUtils;
 import org.apache.hadoop.conf.Configuration;
@@ -29,11 +48,11 @@ import org.apache.hadoop.gateway.services.CLIGatewayServices;
 import org.apache.hadoop.gateway.services.GatewayServices;
 import org.apache.hadoop.gateway.services.Service;
 import org.apache.hadoop.gateway.services.ServiceLifecycleException;
-import org.apache.hadoop.gateway.services.topology.TopologyService;
 import org.apache.hadoop.gateway.services.security.AliasService;
 import org.apache.hadoop.gateway.services.security.KeystoreService;
 import org.apache.hadoop.gateway.services.security.KeystoreServiceException;
 import org.apache.hadoop.gateway.services.security.MasterService;
+import org.apache.hadoop.gateway.services.topology.TopologyService;
 import org.apache.hadoop.gateway.topology.Provider;
 import org.apache.hadoop.gateway.topology.Topology;
 import org.apache.hadoop.gateway.topology.validation.TopologyValidator;
@@ -58,26 +77,7 @@ import org.apache.shiro.util.Factory;
 import org.apache.shiro.util.ThreadContext;
 import org.eclipse.persistence.oxm.MediaType;
 import org.jboss.shrinkwrap.api.exporter.ExplodedExporter;
-import org.jboss.shrinkwrap.api.spec.WebArchive;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLException;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.UUID;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.Console;
+import org.jboss.shrinkwrap.api.spec.EnterpriseArchive;
 /**
  *
  */
@@ -1322,10 +1322,10 @@ public class KnoxCLI extends Configured implements Tool {
     protected String getConfig(Topology t){
       File tmpDir = new File(System.getProperty("java.io.tmpdir"));
       DeploymentFactory.setGatewayServices(services);
-      WebArchive archive = DeploymentFactory.createDeployment(getGatewayConfig(), t);
+      EnterpriseArchive archive = DeploymentFactory.createDeployment(getGatewayConfig(), t);
       File war = archive.as(ExplodedExporter.class).exportExploded(tmpDir, t.getName() + "_deploy.tmp");
       war.deleteOnExit();
-      String config = war.getAbsolutePath() + "/WEB-INF/shiro.ini";
+      String config = war.getAbsolutePath() + "/%2F/WEB-INF/shiro.ini";
       try{
         FileUtils.forceDeleteOnExit(war);
       } catch (IOException e) {

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/main/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoader.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoader.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoader.java
index 0f41b2b..737b405 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoader.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoader.java
@@ -114,7 +114,7 @@ public class ServiceDefinitionsLoader {
     return files;
   }
 
-  private static UrlRewriteRulesDescriptor loadRewriteRules(File servicesDir) {
+  public static UrlRewriteRulesDescriptor loadRewriteRules(File servicesDir) {
     File rewriteFile = new File(servicesDir, REWRITE_FILE);
     if ( rewriteFile.exists() ) {
       InputStream stream = null;

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/main/resources/conf/topology-v1.xsd
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/resources/conf/topology-v1.xsd b/gateway-server/src/main/resources/conf/topology-v1.xsd
index 8ddc7d9..992d8a7 100644
--- a/gateway-server/src/main/resources/conf/topology-v1.xsd
+++ b/gateway-server/src/main/resources/conf/topology-v1.xsd
@@ -18,9 +18,11 @@ limitations under the License.
 <h:schema xmlns:h="http://www.w3.org/2001/XMLSchema">
     <h:element name="topology">
         <h:complexType>
-            <h:choice maxOccurs="unbounded">
+            <h:sequence maxOccurs="1">
 
-                <h:element name="gateway" maxOccurs="1">
+                <h:element name="name" minOccurs="0" maxOccurs="1"/>
+
+                <h:element name="gateway" minOccurs="0" maxOccurs="1">
                     <h:complexType>
                         <h:choice minOccurs="1" maxOccurs="unbounded">
 
@@ -47,24 +49,49 @@ limitations under the License.
                                 </h:complexType>
                             </h:element>
 
-
                         </h:choice>
                     </h:complexType>
                 </h:element>
 
-                <h:element name="service" maxOccurs="unbounded">
+                <h:element name="service" minOccurs="0" maxOccurs="unbounded">
                     <h:complexType>
                         <h:sequence>
                             <h:element name="role" type="h:string" minOccurs="1" maxOccurs="1"/>
-                            <h:element name="url" type="h:string" minOccurs="0"
-                                       maxOccurs="unbounded" />
+                            <h:element name="url" type="h:string" minOccurs="0" maxOccurs="unbounded" />
+                            <h:element name="param" minOccurs="0" maxOccurs="unbounded">
+                                <h:complexType>
+                                    <h:sequence minOccurs="0">
+                                        <h:element name="name" type="h:string" />
+                                        <h:element name="value" type="h:string" />
+                                    </h:sequence>
+                                    <h:attribute name="name" type="h:string" use="optional" />
+                                    <h:attribute name="value" type="h:string" use="optional" />
+                                </h:complexType>
+                            </h:element>
                         </h:sequence>
                     </h:complexType>
-
                 </h:element>
 
+                <h:element name="application" minOccurs="0" maxOccurs="unbounded">
+                    <h:complexType>
+                        <h:sequence>
+                            <h:element name="name" type="h:string" minOccurs="1" maxOccurs="1"/>
+                            <h:element name="url" type="h:string" minOccurs="0" maxOccurs="unbounded" />
+                            <h:element name="param" minOccurs="0" maxOccurs="unbounded">
+                                <h:complexType>
+                                    <h:sequence minOccurs="0">
+                                        <h:element name="name" type="h:string" />
+                                        <h:element name="value" type="h:string" />
+                                    </h:sequence>
+                                    <h:attribute name="name" type="h:string" use="optional" />
+                                    <h:attribute name="value" type="h:string" use="optional" />
+                                </h:complexType>
+                            </h:element>
+                        </h:sequence>
+                    </h:complexType>
+                </h:element>
 
-            </h:choice>
+            </h:sequence>
         </h:complexType>
     </h:element>
 </h:schema>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayGlobalConfigTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayGlobalConfigTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayGlobalConfigTest.java
index 2ba0f7a..445a119 100644
--- a/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayGlobalConfigTest.java
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayGlobalConfigTest.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.gateway;
 
 import org.apache.hadoop.gateway.config.GatewayConfig;
 import org.apache.hadoop.gateway.config.impl.GatewayConfigImpl;
+import org.apache.hadoop.test.TestUtils;
 import org.hamcrest.Matchers;
 import org.junit.Test;
 
@@ -26,6 +27,7 @@ import java.io.File;
 import java.net.URL;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
 import static org.junit.Assert.*;
 
 public class GatewayGlobalConfigTest {
@@ -76,16 +78,22 @@ public class GatewayGlobalConfigTest {
     //assertThat( config.getShiroConfigFile(), is( "shiro.ini") );
   }
 
-  @Test
+  @Test( timeout = TestUtils.SHORT_TIMEOUT )
   public void testDefaultTopologyName() {
     GatewayConfig config = new GatewayConfigImpl();
-    assertThat( config.getDefaultTopologyName(), is( "sandbox" ) );
+    assertThat( config.getDefaultTopologyName(), is( nullValue() ) );
+
+    ((GatewayConfigImpl)config).set("default.app.topology.name", "test-topo-name" );
+    assertThat( config.getDefaultTopologyName(), is( "test-topo-name" ) );
   }
 
-  @Test
+  @Test( timeout = TestUtils.SHORT_TIMEOUT )
   public void testDefaultAppRedirectPath() {
     GatewayConfig config = new GatewayConfigImpl();
-    assertThat( config.getDefaultAppRedirectPath(), is( "/gateway/sandbox" ) );
+    assertThat( config.getDefaultAppRedirectPath(), nullValue() );
+
+    ((GatewayConfigImpl)config).set("default.app.topology.name", "test-topo-name" );
+    assertThat( config.getDefaultAppRedirectPath(), is("/gateway/test-topo-name") );
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.groovy
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.groovy b/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.groovy
deleted file mode 100644
index c292744..0000000
--- a/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.groovy
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.apache.hadoop.gateway.config.impl
-
-import org.junit.Test
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat
-
-/**
- * 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.
- */
-public class GatewayConfigImplTest {
-
-  @Test
-  public void testHttpServerSettings() {
-    GatewayConfigImpl config = new GatewayConfigImpl();
-
-    // Check the defaults.
-    assertThat( config.getHttpServerRequestBuffer(), is( 16*1024 ) );
-    assertThat( config.getHttpServerRequestHeaderBuffer(), is( 8*1024 ) );
-    assertThat( config.getHttpServerResponseBuffer(), is( 32*1024 ) );
-    assertThat( config.getHttpServerResponseHeaderBuffer(), is( 8*1024 ) );
-
-    assertThat( GatewayConfigImpl.HTTP_SERVER_REQUEST_BUFFER, is( "gateway.httpserver.requestBuffer" ) );
-    assertThat( GatewayConfigImpl.HTTP_SERVER_REQUEST_HEADER_BUFFER, is( "gateway.httpserver.requestHeaderBuffer" ) );
-    assertThat( GatewayConfigImpl.HTTP_SERVER_RESPONSE_BUFFER, is( "gateway.httpserver.responseBuffer" ) );
-    assertThat( GatewayConfigImpl.HTTP_SERVER_RESPONSE_HEADER_BUFFER, is( "gateway.httpserver.responseHeaderBuffer" ) );
-
-    config.setInt( GatewayConfigImpl.HTTP_SERVER_REQUEST_BUFFER, 32*1024 );
-    assertThat( config.getHttpServerRequestBuffer(), is( 32*1024 ) );
-
-    config.setInt( GatewayConfigImpl.HTTP_SERVER_REQUEST_HEADER_BUFFER, 4*1024 );
-    assertThat( config.getHttpServerRequestHeaderBuffer(), is( 4*1024 ) );
-
-    config.setInt( GatewayConfigImpl.HTTP_SERVER_RESPONSE_BUFFER, 16*1024 );
-    assertThat( config.getHttpServerResponseBuffer(), is( 16*1024 ) );
-
-    config.setInt( GatewayConfigImpl.HTTP_SERVER_RESPONSE_HEADER_BUFFER, 6*1024 );
-    assertThat( config.getHttpServerResponseHeaderBuffer(), is( 6*1024 ) );
-
-    // Restore the defaults.
-    config.setInt( GatewayConfigImpl.HTTP_SERVER_REQUEST_BUFFER, 16*1024 );
-    config.setInt( GatewayConfigImpl.HTTP_SERVER_REQUEST_HEADER_BUFFER, 8*1024 );
-    config.setInt( GatewayConfigImpl.HTTP_SERVER_RESPONSE_BUFFER, 32*1024 );
-    config.setInt( GatewayConfigImpl.HTTP_SERVER_RESPONSE_HEADER_BUFFER, 8*1024 );
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/a70a3b56/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.java
new file mode 100644
index 0000000..8b94b56
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.java
@@ -0,0 +1,96 @@
+package org.apache.hadoop.gateway.config.impl;
+
+import org.apache.hadoop.test.TestUtils;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+/**
+ * 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.
+ */
+public class GatewayConfigImplTest {
+
+  @Test( timeout = TestUtils.SHORT_TIMEOUT )
+  public void testHttpServerSettings() {
+    GatewayConfigImpl config = new GatewayConfigImpl();
+
+    // Check the defaults.
+    assertThat( config.getHttpServerRequestBuffer(), is( 16*1024 ) );
+    assertThat( config.getHttpServerRequestHeaderBuffer(), is( 8*1024 ) );
+    assertThat( config.getHttpServerResponseBuffer(), is( 32*1024 ) );
+    assertThat( config.getHttpServerResponseHeaderBuffer(), is( 8*1024 ) );
+
+    assertThat( GatewayConfigImpl.HTTP_SERVER_REQUEST_BUFFER, is( "gateway.httpserver.requestBuffer" ) );
+    assertThat( GatewayConfigImpl.HTTP_SERVER_REQUEST_HEADER_BUFFER, is( "gateway.httpserver.requestHeaderBuffer" ) );
+    assertThat( GatewayConfigImpl.HTTP_SERVER_RESPONSE_BUFFER, is( "gateway.httpserver.responseBuffer" ) );
+    assertThat( GatewayConfigImpl.HTTP_SERVER_RESPONSE_HEADER_BUFFER, is( "gateway.httpserver.responseHeaderBuffer" ) );
+
+    config.setInt( GatewayConfigImpl.HTTP_SERVER_REQUEST_BUFFER, 32*1024 );
+    assertThat( config.getHttpServerRequestBuffer(), is( 32*1024 ) );
+
+    config.setInt( GatewayConfigImpl.HTTP_SERVER_REQUEST_HEADER_BUFFER, 4*1024 );
+    assertThat( config.getHttpServerRequestHeaderBuffer(), is( 4*1024 ) );
+
+    config.setInt( GatewayConfigImpl.HTTP_SERVER_RESPONSE_BUFFER, 16*1024 );
+    assertThat( config.getHttpServerResponseBuffer(), is( 16*1024 ) );
+
+    config.setInt( GatewayConfigImpl.HTTP_SERVER_RESPONSE_HEADER_BUFFER, 6*1024 );
+    assertThat( config.getHttpServerResponseHeaderBuffer(), is( 6*1024 ) );
+
+    // Restore the defaults.
+    config.setInt( GatewayConfigImpl.HTTP_SERVER_REQUEST_BUFFER, 16*1024 );
+    config.setInt( GatewayConfigImpl.HTTP_SERVER_REQUEST_HEADER_BUFFER, 8*1024 );
+    config.setInt( GatewayConfigImpl.HTTP_SERVER_RESPONSE_BUFFER, 32*1024 );
+    config.setInt( GatewayConfigImpl.HTTP_SERVER_RESPONSE_HEADER_BUFFER, 8*1024 );
+  }
+
+  @Test( timeout = TestUtils.SHORT_TIMEOUT )
+  public void testGetGatewayDeploymentsBackupVersionLimit() {
+    GatewayConfigImpl config = new GatewayConfigImpl();
+    assertThat( config.getGatewayDeploymentsBackupVersionLimit(), is(5) );
+
+    config.setInt( config.DEPLOYMENTS_BACKUP_VERSION_LIMIT, 3 );
+    assertThat( config.getGatewayDeploymentsBackupVersionLimit(), is(3) );
+
+    config.setInt( config.DEPLOYMENTS_BACKUP_VERSION_LIMIT, -3 );
+    assertThat( config.getGatewayDeploymentsBackupVersionLimit(), is(-1) );
+
+    config.setInt( config.DEPLOYMENTS_BACKUP_VERSION_LIMIT, 0 );
+    assertThat( config.getGatewayDeploymentsBackupVersionLimit(), is(0) );
+  }
+
+  @Test( timeout = TestUtils.SHORT_TIMEOUT )
+  public void testGetGatewayDeploymentsBackupAgeLimit() {
+    GatewayConfigImpl config = new GatewayConfigImpl();
+    assertThat( config.getGatewayDeploymentsBackupAgeLimit(), is(-1L) );
+
+    config.set( config.DEPLOYMENTS_BACKUP_AGE_LIMIT, "1" );
+    assertThat( config.getGatewayDeploymentsBackupAgeLimit(), is(86400000L) );
+
+    config.set( config.DEPLOYMENTS_BACKUP_AGE_LIMIT, "2" );
+    assertThat( config.getGatewayDeploymentsBackupAgeLimit(), is(86400000L*2L) );
+
+    config.set( config.DEPLOYMENTS_BACKUP_AGE_LIMIT, "0" );
+    assertThat( config.getGatewayDeploymentsBackupAgeLimit(), is(0L) );
+
+    config.set( config.DEPLOYMENTS_BACKUP_AGE_LIMIT, "X" );
+    assertThat( config.getGatewayDeploymentsBackupAgeLimit(), is(-1L) );
+  }
+
+
+}