You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by cu...@apache.org on 2017/09/22 00:59:07 UTC

[46/50] [abbrv] hadoop git commit: YARN-5412. Create a proxy chain for ResourceManager REST API in the Router. (Contributed by Giovanni Matteo Fumarola via curino)

YARN-5412. Create a proxy chain for ResourceManager REST API in the Router. (Contributed by Giovanni Matteo Fumarola via curino)

(cherry picked from commit b6240b92abf453affc5fd64e1eedf2d29842aa75)
(cherry picked from commit acda6b96a4e92e432bd1d97fa14004a11e70387e)


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

Branch: refs/heads/branch-2
Commit: bfd967d33866d7a3067f0b7cd107d5d45e4adf6e
Parents: 049f7c8
Author: Carlo Curino <cu...@apache.org>
Authored: Thu Jul 27 14:34:45 2017 -0700
Committer: Carlo Curino <cu...@apache.org>
Committed: Thu Sep 21 17:13:28 2017 -0700

----------------------------------------------------------------------
 .../hadoop/yarn/conf/YarnConfiguration.java     |   24 +
 .../hadoop/yarn/webapp/util/WebAppUtils.java    |   14 +
 .../src/main/resources/yarn-default.xml         |   30 +
 .../resourcemanager/webapp/RMWSConsts.java      |   15 +
 .../resourcemanager/webapp/RMWebAppUtil.java    |   29 +
 .../webapp/RMWebServiceProtocol.java            |  133 +-
 .../resourcemanager/webapp/RMWebServices.java   |    4 +-
 .../webapp/dao/AppAttemptInfo.java              |    5 +-
 .../TestFederationRMStateStoreService.java      |    9 +-
 .../hadoop-yarn-server-router/pom.xml           |   34 +-
 .../hadoop/yarn/server/router/Router.java       |   35 +
 .../webapp/AbstractRESTRequestInterceptor.java  |   89 ++
 .../webapp/DefaultRequestInterceptorREST.java   |  496 +++++++
 .../yarn/server/router/webapp/HTTPMethods.java  |   34 +
 .../router/webapp/RESTRequestInterceptor.java   |  125 ++
 .../yarn/server/router/webapp/RouterWebApp.java |   48 +
 .../router/webapp/RouterWebServiceUtil.java     |  227 +++
 .../server/router/webapp/RouterWebServices.java |  876 ++++++++++++
 .../yarn/server/router/webapp/package-info.java |   20 +
 .../webapp/BaseRouterWebServicesTest.java       |  601 ++++++++
 .../yarn/server/router/webapp/JavaProcess.java  |   52 +
 .../webapp/MockRESTRequestInterceptor.java      |  340 +++++
 .../PassThroughRESTRequestInterceptor.java      |  339 +++++
 .../router/webapp/TestRouterWebServices.java    |  269 ++++
 .../webapp/TestRouterWebServicesREST.java       | 1298 ++++++++++++++++++
 .../src/test/resources/capacity-scheduler.xml   |  111 ++
 .../src/test/resources/log4j.properties         |   19 +
 .../src/test/resources/yarn-site.xml            |   30 +
 28 files changed, 5237 insertions(+), 69 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
index 7adfdf1..34374cf 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
@@ -2629,6 +2629,30 @@ public class YarnConfiguration extends Configuration {
       ROUTER_PREFIX + "submit.retry";
   public static final int DEFAULT_ROUTER_CLIENTRM_SUBMIT_RETRY = 3;
 
+  public static final String ROUTER_WEBAPP_PREFIX = ROUTER_PREFIX + "webapp.";
+
+  /** The address of the Router web application. */
+  public static final String ROUTER_WEBAPP_ADDRESS =
+      ROUTER_WEBAPP_PREFIX + "address";
+
+  public static final int DEFAULT_ROUTER_WEBAPP_PORT = 8089;
+  public static final String DEFAULT_ROUTER_WEBAPP_ADDRESS =
+      "0.0.0.0:" + DEFAULT_ROUTER_WEBAPP_PORT;
+
+  /** The https address of the Router web application. */
+  public static final String ROUTER_WEBAPP_HTTPS_ADDRESS =
+      ROUTER_WEBAPP_PREFIX + "https.address";
+
+  public static final int DEFAULT_ROUTER_WEBAPP_HTTPS_PORT = 8091;
+  public static final String DEFAULT_ROUTER_WEBAPP_HTTPS_ADDRESS =
+      "0.0.0.0:" + DEFAULT_ROUTER_WEBAPP_HTTPS_PORT;
+
+  public static final String ROUTER_WEBAPP_INTERCEPTOR_CLASS_PIPELINE =
+      ROUTER_WEBAPP_PREFIX + "interceptor-class.pipeline";
+  public static final String DEFAULT_ROUTER_WEBAPP_INTERCEPTOR_CLASS =
+      "org.apache.hadoop.yarn.server.router.webapp."
+          + "DefaultRequestInterceptorREST";
+
   ////////////////////////////////
   // Other Configs
   ////////////////////////////////

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java
index a32b2be..d62a810 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java
@@ -129,6 +129,20 @@ public class WebAppUtils {
     return getRMWebAppURLWithoutScheme(conf, false);
   }
 
+  public static String getRouterWebAppURLWithScheme(Configuration conf) {
+    return getHttpSchemePrefix(conf) + getRouterWebAppURLWithoutScheme(conf);
+  }
+
+  public static String getRouterWebAppURLWithoutScheme(Configuration conf) {
+    if (YarnConfiguration.useHttps(conf)) {
+      return conf.get(YarnConfiguration.ROUTER_WEBAPP_HTTPS_ADDRESS,
+          YarnConfiguration.DEFAULT_ROUTER_WEBAPP_HTTPS_ADDRESS);
+    } else {
+      return conf.get(YarnConfiguration.ROUTER_WEBAPP_ADDRESS,
+          YarnConfiguration.DEFAULT_ROUTER_WEBAPP_ADDRESS);
+    }
+  }
+
   public static List<String> getProxyHostsAndPortsForAmFilter(
       Configuration conf) {
     List<String> addrs = new ArrayList<String>();

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
index 998e4cb..122b824 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
@@ -3153,4 +3153,34 @@
     <value></value>
   </property>
 
+  <property>
+    <description>
+      The comma separated list of class names that implement the
+      RequestInterceptor interface. This is used by the RouterWebServices
+      to create the request processing pipeline for users.
+    </description>
+    <name>yarn.router.webapp.interceptor-class.pipeline</name>
+    <value>org.apache.hadoop.yarn.server.router.webapp.DefaultRequestInterceptorREST</value>
+  </property>
+
+  <property>
+    <description>
+      The http address of the Router web application.
+      If only a host is provided as the value,
+      the webapp will be served on a random port.
+    </description>
+    <name>yarn.router.webapp.address</name>
+    <value>0.0.0.0:8089</value>
+  </property>
+
+  <property>
+    <description>
+      The https address of the Router web application.
+      If only a host is provided as the value,
+      the webapp will be served on a random port.
+    </description>
+    <name> yarn.router.webapp.https.address</name>
+    <value>0.0.0.0:8091</value>
+  </property>
+
 </configuration>

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java
index 23d4bb1..5a945da 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java
@@ -168,6 +168,12 @@ public final class RMWSConsts {
    */
   public static final String APPS_TIMEOUT = "/apps/{appid}/timeout";
 
+  /**
+   * Path for {@code RouterWebServices#getContainer}.
+   */
+  public static final String GET_CONTAINER =
+      "/apps/{appid}/appattempts/{appattemptid}/containers/{containerid}";
+
   // ----------------QueryParams for RMWebServiceProtocol----------------
 
   public static final String TIME = "time";
@@ -194,6 +200,15 @@ public final class RMWSConsts {
   public static final String END_TIME = "end-time";
   public static final String INCLUDE_RESOURCE = "include-resource-allocations";
   public static final String TYPE = "type";
+  public static final String CONTAINERID = "containerid";
+  public static final String APPATTEMPTS = "appattempts";
+  public static final String TIMEOUTS = "timeouts";
+  public static final String PRIORITY = "priority";
+  public static final String TIMEOUT = "timeout";
+  public static final String ATTEMPTS = "appattempts";
+  public static final String GET_LABELS = "get-labels";
+  public static final String DESELECTS = "deSelects";
+  public static final String CONTAINERS = "containers";
 
   private RMWSConsts() {
     // not called

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebAppUtil.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebAppUtil.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebAppUtil.java
index f529dc2..ce05456 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebAppUtil.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebAppUtil.java
@@ -20,10 +20,13 @@ package org.apache.hadoop.yarn.server.resourcemanager.webapp;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.security.Principal;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.servlet.http.HttpServletRequest;
+
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -341,4 +344,30 @@ public final class RMWebAppUtil {
         logAggregationContextInfo.getLogAggregationPolicyClassName(),
         logAggregationContextInfo.getLogAggregationPolicyParameters());
   }
+
+ /**
+   * Helper method to retrieve the UserGroupInformation from the
+   * HttpServletRequest.
+   *
+   * @param hsr the servlet request
+   * @param usePrincipal true if we need to use the principal user, remote
+   *          otherwise.
+   * @return the user group information of the caller.
+   **/
+  public static UserGroupInformation getCallerUserGroupInformation(
+      HttpServletRequest hsr, boolean usePrincipal) {
+
+    String remoteUser = hsr.getRemoteUser();
+    if (usePrincipal) {
+      Principal princ = hsr.getUserPrincipal();
+      remoteUser = princ == null ? null : princ.getName();
+    }
+
+    UserGroupInformation callerUGI = null;
+    if (remoteUser != null) {
+      callerUGI = UserGroupInformation.createRemoteUser(remoteUser);
+    }
+
+    return callerUGI;
+  }
 }

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServiceProtocol.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServiceProtocol.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServiceProtocol.java
index 250cb95..062ca4c 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServiceProtocol.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServiceProtocol.java
@@ -108,7 +108,7 @@ public interface RMWebServiceProtocol {
    * This method dumps the scheduler logs for the time got in input, and it is
    * reachable by using {@link RMWSConsts#SCHEDULER_LOGS}.
    *
-   * @param time the period of time
+   * @param time the period of time. It is a FormParam.
    * @param hsr the servlet request
    * @return the result of the operation
    * @throws IOException when it cannot create dump log file
@@ -121,7 +121,7 @@ public interface RMWebServiceProtocol {
    * reachable by using {@link RMWSConsts#NODES}.
    *
    * @see ApplicationClientProtocol#getClusterNodes
-   * @param states the states we want to filter
+   * @param states the states we want to filter. It is a QueryParam.
    * @return all nodes in the cluster. If the states param is given, returns all
    *         nodes that are in the comma-separated list of states
    */
@@ -131,7 +131,8 @@ public interface RMWebServiceProtocol {
    * This method retrieves a specific node information, and it is reachable by
    * using {@link RMWSConsts#NODES_NODEID}.
    *
-   * @param nodeId the node we want to retrieve the information
+   * @param nodeId the node we want to retrieve the information. It is a
+   *          PathParam.
    * @return the information about the node in input
    */
   NodeInfo getNode(String nodeId);
@@ -142,19 +143,25 @@ public interface RMWebServiceProtocol {
    *
    * @see ApplicationClientProtocol#getApplications
    * @param hsr the servlet request
-   * @param stateQuery right now the stateQuery is deprecated
-   * @param statesQuery filter the result by states
-   * @param finalStatusQuery filter the result by final states
-   * @param userQuery filter the result by user
-   * @param queueQuery filter the result by queue
-   * @param count set a limit of the result
-   * @param startedBegin filter the result by started begin time
-   * @param startedEnd filter the result by started end time
-   * @param finishBegin filter the result by finish begin time
-   * @param finishEnd filter the result by finish end time
-   * @param applicationTypes filter the result by types
-   * @param applicationTags filter the result by tags
-   * @param unselectedFields De-selected params to avoid from report
+   * @param stateQuery right now the stateQuery is deprecated. It is a
+   *          QueryParam.
+   * @param statesQuery filter the result by states. It is a QueryParam.
+   * @param finalStatusQuery filter the result by final states. It is a
+   *          QueryParam.
+   * @param userQuery filter the result by user. It is a QueryParam.
+   * @param queueQuery filter the result by queue. It is a QueryParam.
+   * @param count set a limit of the result. It is a QueryParam.
+   * @param startedBegin filter the result by started begin time. It is a
+   *          QueryParam.
+   * @param startedEnd filter the result by started end time. It is a
+   *          QueryParam.
+   * @param finishBegin filter the result by finish begin time. It is a
+   *          QueryParam.
+   * @param finishEnd filter the result by finish end time. It is a QueryParam.
+   * @param applicationTypes filter the result by types. It is a QueryParam.
+   * @param applicationTags filter the result by tags. It is a QueryParam.
+   * @param unselectedFields De-selected params to avoid from report. It is a
+   *          QueryParam.
    * @return all apps in the cluster
    */
   @SuppressWarnings("checkstyle:parameternumber")
@@ -169,7 +176,8 @@ public interface RMWebServiceProtocol {
    * reachable by using {@link RMWSConsts#SCHEDULER_ACTIVITIES}.
    *
    * @param hsr the servlet request
-   * @param nodeId the node we want to retrieve the activities
+   * @param nodeId the node we want to retrieve the activities. It is a
+   *          QueryParam.
    * @return all the activities in the specific node
    */
   ActivitiesInfo getActivities(HttpServletRequest hsr, String nodeId);
@@ -180,8 +188,10 @@ public interface RMWebServiceProtocol {
    * {@link RMWSConsts#SCHEDULER_APP_ACTIVITIES}.
    *
    * @param hsr the servlet request
-   * @param appId the applicationId we want to retrieve the activities
-   * @param time for how long we want to retrieve the activities
+   * @param appId the applicationId we want to retrieve the activities. It is a
+   *          QueryParam.
+   * @param time for how long we want to retrieve the activities. It is a
+   *          QueryParam.
    * @return all the activities about a specific app for a specific time
    */
   AppActivitiesInfo getAppActivities(HttpServletRequest hsr, String appId,
@@ -192,8 +202,8 @@ public interface RMWebServiceProtocol {
    * reachable by using {@link RMWSConsts#APP_STATISTICS}.
    *
    * @param hsr the servlet request
-   * @param stateQueries filter the result by states
-   * @param typeQueries filter the result by type names
+   * @param stateQueries filter the result by states. It is a QueryParam.
+   * @param typeQueries filter the result by type names. It is a QueryParam.
    * @return the application's statistics for specific states and types
    */
   ApplicationStatisticsInfo getAppStatistics(HttpServletRequest hsr,
@@ -205,8 +215,10 @@ public interface RMWebServiceProtocol {
    *
    * @see ApplicationClientProtocol#getApplicationReport
    * @param hsr the servlet request
-   * @param appId the Id of the application we want the report
-   * @param unselectedFields De-selected params to avoid from report
+   * @param appId the Id of the application we want the report. It is a
+   *          PathParam.
+   * @param unselectedFields De-selected param list to avoid from report. It is
+   *          a QueryParam.
    * @return the app report for a specific application
    */
   AppInfo getApp(HttpServletRequest hsr, String appId,
@@ -217,7 +229,8 @@ public interface RMWebServiceProtocol {
    * using {@link RMWSConsts#APPS_APPID_STATE}.
    *
    * @param hsr the servlet request
-   * @param appId the Id of the application we want the state
+   * @param appId the Id of the application we want the state. It is a
+   *          PathParam.
    * @return the state for a specific application
    * @throws AuthorizationException if the user is not authorized
    */
@@ -228,9 +241,10 @@ public interface RMWebServiceProtocol {
    * This method updates the state of the app in input, and it is reachable by
    * using {@link RMWSConsts#APPS_APPID_STATE}.
    *
-   * @param targetState the target state for the app
+   * @param targetState the target state for the app. It is a content param.
    * @param hsr the servlet request
-   * @param appId the Id of the application we want to update the state
+   * @param appId the Id of the application we want to update the state. It is a
+   *          PathParam.
    * @return Response containing the status code
    * @throws AuthorizationException if the user is not authorized to invoke this
    *           method
@@ -259,7 +273,7 @@ public interface RMWebServiceProtocol {
    * cluster, and it is reachable by using {@link RMWSConsts#LABEL_MAPPINGS}.
    *
    * @see ApplicationClientProtocol#getLabelsToNodes
-   * @param labels filter the result by node labels
+   * @param labels filter the result by node labels. It is a QueryParam.
    * @return all the nodes within multiple node labels
    * @throws IOException if an IOException happened
    */
@@ -270,7 +284,7 @@ public interface RMWebServiceProtocol {
    * reachable by using {@link RMWSConsts#REPLACE_NODE_TO_LABELS}.
    *
    * @see ResourceManagerAdministrationProtocol#replaceLabelsOnNode
-   * @param newNodeToLabels the list of new labels
+   * @param newNodeToLabels the list of new labels. It is a content param.
    * @param hsr the servlet request
    * @return Response containing the status code
    * @throws Exception if an exception happened
@@ -283,9 +297,10 @@ public interface RMWebServiceProtocol {
    * reachable by using {@link RMWSConsts#NODES_NODEID_REPLACE_LABELS}.
    *
    * @see ResourceManagerAdministrationProtocol#replaceLabelsOnNode
-   * @param newNodeLabelsName the list of new labels
+   * @param newNodeLabelsName the list of new labels. It is a QueryParam.
    * @param hsr the servlet request
-   * @param nodeId the node we want to replace the node labels
+   * @param nodeId the node we want to replace the node labels. It is a
+   *          PathParam.
    * @return Response containing the status code
    * @throws Exception if an exception happened
    */
@@ -309,7 +324,7 @@ public interface RMWebServiceProtocol {
    * reachable by using {@link RMWSConsts#ADD_NODE_LABELS}.
    *
    * @see ResourceManagerAdministrationProtocol#addToClusterNodeLabels
-   * @param newNodeLabels the node labels to add
+   * @param newNodeLabels the node labels to add. It is a content param.
    * @param hsr the servlet request
    * @return Response containing the status code
    * @throws Exception in case of bad request
@@ -322,7 +337,7 @@ public interface RMWebServiceProtocol {
    * reachable by using {@link RMWSConsts#REMOVE_NODE_LABELS}.
    *
    * @see ResourceManagerAdministrationProtocol#removeFromClusterNodeLabels
-   * @param oldNodeLabels the node labels to remove
+   * @param oldNodeLabels the node labels to remove. It is a QueryParam.
    * @param hsr the servlet request
    * @return Response containing the status code
    * @throws Exception in case of bad request
@@ -335,7 +350,8 @@ public interface RMWebServiceProtocol {
    * reachable by using {@link RMWSConsts#NODES_NODEID_GETLABELS}.
    *
    * @param hsr the servlet request
-   * @param nodeId the node we want to get all the node labels
+   * @param nodeId the node we want to get all the node labels. It is a
+   *          PathParam.
    * @return all the labels for a specific node.
    * @throws IOException if an IOException happened
    */
@@ -347,7 +363,7 @@ public interface RMWebServiceProtocol {
    * by using {@link RMWSConsts#APPS_APPID_PRIORITY}.
    *
    * @param hsr the servlet request
-   * @param appId the app we want to get the priority
+   * @param appId the app we want to get the priority. It is a PathParam.
    * @return the priority for a specific application
    * @throws AuthorizationException in case of the user is not authorized
    */
@@ -358,9 +374,11 @@ public interface RMWebServiceProtocol {
    * This method updates the priority for a specific application, and it is
    * reachable by using {@link RMWSConsts#APPS_APPID_PRIORITY}.
    *
-   * @param targetPriority the priority we want to set for the app
+   * @param targetPriority the priority we want to set for the app. It is a
+   *          content param.
    * @param hsr the servlet request
-   * @param appId the application we want to update its priority
+   * @param appId the application we want to update its priority. It is a
+   *          PathParam.
    * @return Response containing the status code
    * @throws AuthorizationException if the user is not authenticated
    * @throws YarnException if the target is null
@@ -376,7 +394,8 @@ public interface RMWebServiceProtocol {
    * using {@link RMWSConsts#APPS_APPID_QUEUE}.
    *
    * @param hsr the servlet request
-   * @param appId the application we want to retrieve its queue
+   * @param appId the application we want to retrieve its queue. It is a
+   *          PathParam.
    * @return the Queue for a specific application.
    * @throws AuthorizationException if the user is not authenticated
    */
@@ -387,9 +406,10 @@ public interface RMWebServiceProtocol {
    * This method updates the queue for a specific application, and it is
    * reachable by using {@link RMWSConsts#APPS_APPID_QUEUE}.
    *
-   * @param targetQueue the queue we want to set
+   * @param targetQueue the queue we want to set. It is a content param.
    * @param hsr the servlet request
-   * @param appId the application we want to change its queue
+   * @param appId the application we want to change its queue. It is a
+   *          PathParam.
    * @return Response containing the status code
    * @throws AuthorizationException if the user is not authenticated
    * @throws YarnException if the app is not found
@@ -424,7 +444,7 @@ public interface RMWebServiceProtocol {
    * @see ApplicationClientProtocol#submitApplication
    *
    * @param newApp structure containing information to construct the
-   *          ApplicationSubmissionContext
+   *          ApplicationSubmissionContext. It is a content param.
    * @param hsr the servlet request
    * @return Response containing the status code
    * @throws AuthorizationException if the user is not authorized to invoke this
@@ -441,7 +461,7 @@ public interface RMWebServiceProtocol {
    * by using {@link RMWSConsts#DELEGATION_TOKEN}.
    *
    * @see ApplicationBaseProtocol#getDelegationToken
-   * @param tokenData the token to delegate
+   * @param tokenData the token to delegate. It is a content param.
    * @param hsr the servlet request
    * @return Response containing the status code
    * @throws AuthorizationException if Kerberos auth failed
@@ -508,7 +528,7 @@ public interface RMWebServiceProtocol {
    * @see ApplicationClientProtocol#submitReservation
    *
    * @param resContext provides information to construct the
-   *          ReservationSubmissionRequest
+   *          ReservationSubmissionRequest. It is a content param.
    * @param hsr the servlet request
    * @return Response containing the status code
    * @throws AuthorizationException if the user is not authorized to invoke this
@@ -527,7 +547,7 @@ public interface RMWebServiceProtocol {
    * @see ApplicationClientProtocol#updateReservation
    *
    * @param resContext provides information to construct the
-   *          ReservationUpdateRequest
+   *          ReservationUpdateRequest. It is a content param.
    * @param hsr the servlet request
    * @return Response containing the status code
    * @throws AuthorizationException if the user is not authorized to invoke this
@@ -546,7 +566,7 @@ public interface RMWebServiceProtocol {
    * @see ApplicationClientProtocol#deleteReservation
    *
    * @param resContext provides information to construct the
-   *          ReservationDeleteRequest
+   *          ReservationDeleteRequest. It is a content param.
    * @param hsr the servlet request
    * @return Response containing the status code
    * @throws AuthorizationException when the user group information cannot be
@@ -566,12 +586,13 @@ public interface RMWebServiceProtocol {
    * reachable by using {@link RMWSConsts#RESERVATION_LIST}.
    *
    * @see ApplicationClientProtocol#listReservations
-   * @param queue filter the result by queue
-   * @param reservationId filter the result by reservationId
-   * @param startTime filter the result by start time
-   * @param endTime filter the result by end time
+   * @param queue filter the result by queue. It is a QueryParam.
+   * @param reservationId filter the result by reservationId. It is a
+   *          QueryParam.
+   * @param startTime filter the result by start time. It is a QueryParam.
+   * @param endTime filter the result by end time. It is a QueryParam.
    * @param includeResourceAllocations true if the resource allocation should be
-   *          in the result, false otherwise
+   *          in the result, false otherwise. It is a QueryParam.
    * @param hsr the servlet request
    * @return Response containing the status code
    * @throws Exception in case of bad request
@@ -586,8 +607,8 @@ public interface RMWebServiceProtocol {
    * {@link RMWSConsts#APPS_TIMEOUTS_TYPE}.
    *
    * @param hsr the servlet request
-   * @param appId the application we want to get the timeout
-   * @param type the type of the timeouts
+   * @param appId the application we want to get the timeout. It is a PathParam.
+   * @param type the type of the timeouts. It is a PathParam.
    * @return the timeout for a specific application with a specific type.
    * @throws AuthorizationException if the user is not authorized
    */
@@ -599,7 +620,8 @@ public interface RMWebServiceProtocol {
    * reachable by using {@link RMWSConsts#APPS_TIMEOUTS}.
    *
    * @param hsr the servlet request
-   * @param appId the application we want to get the timeouts
+   * @param appId the application we want to get the timeouts. It is a
+   *          PathParam.
    * @return the timeouts for a specific application
    * @throws AuthorizationException if the user is not authorized
    */
@@ -611,9 +633,9 @@ public interface RMWebServiceProtocol {
    * reachable by using {@link RMWSConsts#APPS_TIMEOUT}.
    *
    * @see ApplicationClientProtocol#updateApplicationTimeouts
-   * @param appTimeout the appTimeoutInfo
+   * @param appTimeout the appTimeoutInfo. It is a content param.
    * @param hsr the servlet request
-   * @param appId the application we want to update
+   * @param appId the application we want to update. It is a PathParam.
    * @return Response containing the status code
    * @throws AuthorizationException if the user is not authorized to invoke this
    *           method
@@ -631,7 +653,8 @@ public interface RMWebServiceProtocol {
    *
    * @see ApplicationBaseProtocol#getApplicationAttempts
    * @param hsr the servlet request
-   * @param appId the application we want to get the attempts
+   * @param appId the application we want to get the attempts. It is a
+   *          PathParam.
    * @return all the attempts info for a specific application
    */
   AppAttemptsInfo getAppAttempts(HttpServletRequest hsr, String appId);

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java
index b8bd9fb..166a4c9 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java
@@ -435,7 +435,7 @@ public class RMWebServices extends WebServices implements RMWebServiceProtocol {
       @QueryParam(RMWSConsts.FINISHED_TIME_END) String finishEnd,
       @QueryParam(RMWSConsts.APPLICATION_TYPES) Set<String> applicationTypes,
       @QueryParam(RMWSConsts.APPLICATION_TAGS) Set<String> applicationTags,
-      @QueryParam("deSelects") Set<String> unselectedFields) {
+      @QueryParam(RMWSConsts.DESELECTS) Set<String> unselectedFields) {
     boolean checkCount = false;
     boolean checkStart = false;
     boolean checkEnd = false;
@@ -818,7 +818,7 @@ public class RMWebServices extends WebServices implements RMWebServiceProtocol {
   @Override
   public AppInfo getApp(@Context HttpServletRequest hsr,
       @PathParam(RMWSConsts.APPID) String appId,
-      @QueryParam("deSelects") Set<String> unselectedFields) {
+      @QueryParam(RMWSConsts.DESELECTS) Set<String> unselectedFields) {
     init();
     ApplicationId id = WebAppUtils.parseApplicationId(recordFactory, appId);
     RMApp app = rm.getRMContext().getRMApps().get(id);

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppAttemptInfo.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppAttemptInfo.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppAttemptInfo.java
index 55bf999..82a946e 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppAttemptInfo.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppAttemptInfo.java
@@ -27,7 +27,6 @@ import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager;
 import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt;
 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.AbstractYarnScheduler;
 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerApplicationAttempt;
-import org.apache.hadoop.yarn.util.ConverterUtils;
 import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
 
 @XmlRootElement(name = "appAttempt")
@@ -106,4 +105,8 @@ public class AppAttemptInfo {
   public String getLogsLink() {
     return this.logsLink;
   }
+
+  public String getAppAttemptId() {
+    return this.appAttemptId;
+  }
 }

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/federation/TestFederationRMStateStoreService.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/federation/TestFederationRMStateStoreService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/federation/TestFederationRMStateStoreService.java
index d92a793..e5e156d 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/federation/TestFederationRMStateStoreService.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/federation/TestFederationRMStateStoreService.java
@@ -29,6 +29,7 @@ import org.apache.hadoop.yarn.conf.YarnConfiguration;
 import org.apache.hadoop.yarn.exceptions.YarnException;
 import org.apache.hadoop.yarn.server.federation.store.FederationStateStore;
 import org.apache.hadoop.yarn.server.federation.store.records.GetSubClusterInfoRequest;
+import org.apache.hadoop.yarn.server.federation.store.records.GetSubClusterInfoResponse;
 import org.apache.hadoop.yarn.server.federation.store.records.SubClusterDeregisterRequest;
 import org.apache.hadoop.yarn.server.federation.store.records.SubClusterId;
 import org.apache.hadoop.yarn.server.federation.store.records.SubClusterInfo;
@@ -86,12 +87,8 @@ public class TestFederationRMStateStoreService {
     // Initially there should be no entry for the sub-cluster
     rm.init(conf);
     stateStore = rm.getFederationStateStoreService().getStateStoreClient();
-    try {
-      stateStore.getSubCluster(request);
-      Assert.fail("There should be no entry for the sub-cluster.");
-    } catch (YarnException e) {
-      Assert.assertTrue(e.getMessage().endsWith("does not exist"));
-    }
+    GetSubClusterInfoResponse response = stateStore.getSubCluster(request);
+    Assert.assertNull(response);
 
     // Validate if sub-cluster is registered
     rm.start();

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/pom.xml
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/pom.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/pom.xml
index 4eea9a6..e8b4d56 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/pom.xml
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/pom.xml
@@ -50,6 +50,25 @@
 
     <dependency>
       <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-yarn-server-common</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-yarn-server-common</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <!-- 'mvn dependency:analyze' fails to detect use of this dependency -->
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-common</artifactId>
       <type>test-jar</type>
       <scope>test</scope>
@@ -57,21 +76,26 @@
 
     <dependency>
       <groupId>org.apache.hadoop</groupId>
-      <artifactId>hadoop-yarn-server-common</artifactId>
+      <artifactId>hadoop-yarn-server-resourcemanager</artifactId>
     </dependency>
 
     <dependency>
       <groupId>org.apache.hadoop</groupId>
-      <artifactId>hadoop-yarn-server-common</artifactId>
-      <type>test-jar</type>
+      <artifactId>hadoop-yarn-server-nodemanager</artifactId>
       <scope>test</scope>
     </dependency>
 
     <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
       <scope>test</scope>
     </dependency>
+
+    <dependency>
+      <groupId>com.google.inject</groupId>
+      <artifactId>guice</artifactId>
+    </dependency>
+
   </dependencies>
 
   <build>

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/Router.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/Router.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/Router.java
index d2eee5a..121e534 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/Router.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/Router.java
@@ -21,6 +21,7 @@ package org.apache.hadoop.yarn.server.router;
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import org.apache.hadoop.classification.InterfaceAudience.Private;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.service.CompositeService;
 import org.apache.hadoop.util.ShutdownHookManager;
@@ -28,11 +29,19 @@ import org.apache.hadoop.util.StringUtils;
 import org.apache.hadoop.yarn.YarnUncaughtExceptionHandler;
 import org.apache.hadoop.yarn.conf.YarnConfiguration;
 import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWebAppUtil;
 import org.apache.hadoop.yarn.server.router.clientrm.RouterClientRMService;
 import org.apache.hadoop.yarn.server.router.rmadmin.RouterRMAdminService;
+import org.apache.hadoop.yarn.server.router.webapp.RouterWebApp;
+import org.apache.hadoop.yarn.webapp.WebApp;
+import org.apache.hadoop.yarn.webapp.WebApps;
+import org.apache.hadoop.yarn.webapp.WebApps.Builder;
+import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.annotations.VisibleForTesting;
+
 /**
  * The router is a stateless YARN component which is the entry point to the
  * cluster. It can be deployed on multiple nodes behind a Virtual IP (VIP) with
@@ -56,6 +65,9 @@ public class Router extends CompositeService {
   private AtomicBoolean isStopping = new AtomicBoolean(false);
   private RouterClientRMService clientRMProxyService;
   private RouterRMAdminService rmAdminProxyService;
+  private WebApp webApp;
+  @VisibleForTesting
+  protected String webAppAddress;
 
   /**
    * Priority of the Router shutdown hook.
@@ -79,6 +91,10 @@ public class Router extends CompositeService {
     // RMAdmin Proxy
     rmAdminProxyService = createRMAdminProxyService();
     addService(rmAdminProxyService);
+    // WebService
+    webAppAddress = WebAppUtils.getWebAppBindURL(this.conf,
+        YarnConfiguration.ROUTER_BIND_HOST,
+        WebAppUtils.getRouterWebAppURLWithoutScheme(this.conf));
     super.serviceInit(conf);
   }
 
@@ -89,11 +105,15 @@ public class Router extends CompositeService {
     } catch (IOException e) {
       throw new YarnRuntimeException("Failed Router login", e);
     }
+    startWepApp();
     super.serviceStart();
   }
 
   @Override
   protected void serviceStop() throws Exception {
+    if (webApp != null) {
+      webApp.stop();
+    }
     if (isStopping.getAndSet(true)) {
       return;
     }
@@ -117,6 +137,21 @@ public class Router extends CompositeService {
     return new RouterRMAdminService();
   }
 
+  @Private
+  public WebApp getWebapp() {
+    return this.webApp;
+  }
+
+  @VisibleForTesting
+  public void startWepApp() {
+
+    RMWebAppUtil.setupSecurityAndFilters(conf, null);
+
+    Builder<Object> builder =
+        WebApps.$for("cluster", null, null, "ws").with(conf).at(webAppAddress);
+    webApp = builder.start(new RouterWebApp(this));
+  }
+
   public static void main(String[] argv) {
     Configuration conf = new YarnConfiguration();
     Thread

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/AbstractRESTRequestInterceptor.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/AbstractRESTRequestInterceptor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/AbstractRESTRequestInterceptor.java
new file mode 100644
index 0000000..a2d78a4
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/AbstractRESTRequestInterceptor.java
@@ -0,0 +1,89 @@
+/**
+ * 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.yarn.server.router.webapp;
+
+import org.apache.hadoop.conf.Configuration;
+
+/**
+ * Extends the RequestInterceptor class and provides common functionality which
+ * can be used and/or extended by other concrete intercepter classes.
+ */
+public abstract class AbstractRESTRequestInterceptor
+    implements RESTRequestInterceptor {
+
+  private Configuration conf;
+  private RESTRequestInterceptor nextInterceptor;
+
+  /**
+   * Sets the {@link RESTRequestInterceptor} in the chain.
+   */
+  @Override
+  public void setNextInterceptor(RESTRequestInterceptor nextInterceptor) {
+    this.nextInterceptor = nextInterceptor;
+  }
+
+  /**
+   * Sets the {@link Configuration}.
+   */
+
+  @Override
+  public void setConf(Configuration conf) {
+    this.conf = conf;
+    if (this.nextInterceptor != null) {
+      this.nextInterceptor.setConf(conf);
+    }
+  }
+
+  /**
+   * Gets the {@link Configuration}.
+   */
+  @Override
+  public Configuration getConf() {
+    return this.conf;
+  }
+
+  /**
+   * Initializes the {@link RESTRequestInterceptor}.
+   */
+  @Override
+  public void init(String user) {
+    if (this.nextInterceptor != null) {
+      this.nextInterceptor.init(user);
+    }
+  }
+
+  /**
+   * Disposes the {@link RESTRequestInterceptor}.
+   */
+  @Override
+  public void shutdown() {
+    if (this.nextInterceptor != null) {
+      this.nextInterceptor.shutdown();
+    }
+  }
+
+  /**
+   * Gets the next {@link RESTRequestInterceptor} in the chain.
+   */
+  @Override
+  public RESTRequestInterceptor getNextInterceptor() {
+    return this.nextInterceptor;
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/DefaultRequestInterceptorREST.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/DefaultRequestInterceptorREST.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/DefaultRequestInterceptorREST.java
new file mode 100644
index 0000000..aa8e3eb
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/DefaultRequestInterceptorREST.java
@@ -0,0 +1,496 @@
+/**
+ * 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.yarn.server.router.webapp;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Response;
+
+import org.apache.hadoop.security.authorize.AuthorizationException;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWSConsts;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ActivitiesInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppActivitiesInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppAttemptsInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppPriority;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppQueue;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppState;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppTimeoutInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppTimeoutsInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ApplicationStatisticsInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ApplicationSubmissionContextInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppsInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterMetricsInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.DelegationToken;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.LabelsToNodesInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerTypeInfo;
+import org.apache.hadoop.yarn.server.webapp.dao.AppAttemptInfo;
+import org.apache.hadoop.yarn.server.webapp.dao.ContainerInfo;
+import org.apache.hadoop.yarn.server.webapp.dao.ContainersInfo;
+import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
+
+/**
+ * Extends the AbstractRequestInterceptorClient class and provides an
+ * implementation that simply forwards the client requests to the resource
+ * manager.
+ */
+public final class DefaultRequestInterceptorREST
+    extends AbstractRESTRequestInterceptor {
+
+  private String webAppAddress;
+
+  @Override
+  public void init(String user) {
+    webAppAddress = WebAppUtils.getRMWebAppURLWithScheme(getConf());
+  }
+
+  @Override
+  public ClusterInfo get() {
+    return getClusterInfo();
+  }
+
+  @Override
+  public ClusterInfo getClusterInfo() {
+    return RouterWebServiceUtil.genericForward(webAppAddress, null,
+        ClusterInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.INFO, null, null);
+  }
+
+  @Override
+  public ClusterMetricsInfo getClusterMetricsInfo() {
+    return RouterWebServiceUtil.genericForward(webAppAddress, null,
+        ClusterMetricsInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.METRICS, null, null);
+  }
+
+  @Override
+  public SchedulerTypeInfo getSchedulerInfo() {
+    return RouterWebServiceUtil.genericForward(webAppAddress, null,
+        SchedulerTypeInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.SCHEDULER, null, null);
+  }
+
+  @Override
+  public String dumpSchedulerLogs(String time, HttpServletRequest hsr)
+      throws IOException {
+    // time is specified inside hsr
+    return RouterWebServiceUtil.genericForward(webAppAddress, null,
+        String.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.SCHEDULER_LOGS, null, null);
+  }
+
+  @Override
+  public NodesInfo getNodes(String states) {
+    // states will be part of additionalParam
+    Map<String, String[]> additionalParam = new HashMap<String, String[]>();
+    additionalParam.put(RMWSConsts.STATES, new String[] {states});
+    return RouterWebServiceUtil.genericForward(webAppAddress, null,
+        NodesInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.NODES, null,
+        additionalParam);
+  }
+
+  @Override
+  public NodeInfo getNode(String nodeId) {
+    return RouterWebServiceUtil.genericForward(webAppAddress, null,
+        NodeInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.NODES + "/" + nodeId, null,
+        null);
+  }
+
+  @Override
+  public AppsInfo getApps(HttpServletRequest hsr, String stateQuery,
+      Set<String> statesQuery, String finalStatusQuery, String userQuery,
+      String queueQuery, String count, String startedBegin, String startedEnd,
+      String finishBegin, String finishEnd, Set<String> applicationTypes,
+      Set<String> applicationTags, Set<String> unselectedFields) {
+    // all the params are specified inside hsr
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        AppsInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.APPS, null, null);
+  }
+
+  @Override
+  public ActivitiesInfo getActivities(HttpServletRequest hsr, String nodeId) {
+    // nodeId is specified inside hsr
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        ActivitiesInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.SCHEDULER_ACTIVITIES, null,
+        null);
+  }
+
+  @Override
+  public AppActivitiesInfo getAppActivities(HttpServletRequest hsr,
+      String appId, String time) {
+    // time and appId are specified inside hsr
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        AppActivitiesInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.SCHEDULER_APP_ACTIVITIES,
+        null, null);
+  }
+
+  @Override
+  public ApplicationStatisticsInfo getAppStatistics(HttpServletRequest hsr,
+      Set<String> stateQueries, Set<String> typeQueries) {
+    // stateQueries and typeQueries are specified inside hsr
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        ApplicationStatisticsInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.APP_STATISTICS, null, null);
+  }
+
+  @Override
+  public AppInfo getApp(HttpServletRequest hsr, String appId,
+      Set<String> unselectedFields) {
+    // unselectedFields is specified inside hsr
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        AppInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.APPS + "/" + appId, null,
+        null);
+  }
+
+  @Override
+  public AppState getAppState(HttpServletRequest hsr, String appId)
+      throws AuthorizationException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        AppState.class, HTTPMethods.GET, RMWSConsts.RM_WEB_SERVICE_PATH
+            + RMWSConsts.APPS + "/" + appId + "/" + RMWSConsts.STATE,
+        null, null);
+  }
+
+  @Override
+  public Response updateAppState(AppState targetState, HttpServletRequest hsr,
+      String appId) throws AuthorizationException, YarnException,
+      InterruptedException, IOException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.PUT, RMWSConsts.RM_WEB_SERVICE_PATH
+            + RMWSConsts.APPS + "/" + appId + "/" + RMWSConsts.STATE,
+        targetState, null);
+  }
+
+  @Override
+  public NodeToLabelsInfo getNodeToLabels(HttpServletRequest hsr)
+      throws IOException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        NodeToLabelsInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.GET_NODE_TO_LABELS, null,
+        null);
+  }
+
+  @Override
+  public LabelsToNodesInfo getLabelsToNodes(Set<String> labels)
+      throws IOException {
+    // labels will be part of additionalParam
+    Map<String, String[]> additionalParam = new HashMap<String, String[]>();
+    additionalParam.put(RMWSConsts.LABELS,
+        labels.toArray(new String[labels.size()]));
+    return RouterWebServiceUtil.genericForward(webAppAddress, null,
+        LabelsToNodesInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.LABEL_MAPPINGS, null,
+        additionalParam);
+  }
+
+  @Override
+  public Response replaceLabelsOnNodes(NodeToLabelsEntryList newNodeToLabels,
+      HttpServletRequest hsr) throws IOException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.POST,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.REPLACE_NODE_TO_LABELS,
+        newNodeToLabels, null);
+  }
+
+  @Override
+  public Response replaceLabelsOnNode(Set<String> newNodeLabelsName,
+      HttpServletRequest hsr, String nodeId) throws Exception {
+    // newNodeLabelsName is specified inside hsr
+    return RouterWebServiceUtil
+        .genericForward(webAppAddress, hsr,
+            Response.class, HTTPMethods.POST, RMWSConsts.RM_WEB_SERVICE_PATH
+                + RMWSConsts.NODES + "/" + nodeId + "/replace-labels",
+            null, null);
+  }
+
+  @Override
+  public NodeLabelsInfo getClusterNodeLabels(HttpServletRequest hsr)
+      throws IOException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        NodeLabelsInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.GET_NODE_LABELS, null,
+        null);
+  }
+
+  @Override
+  public Response addToClusterNodeLabels(NodeLabelsInfo newNodeLabels,
+      HttpServletRequest hsr) throws Exception {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.POST,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.ADD_NODE_LABELS,
+        newNodeLabels, null);
+  }
+
+  @Override
+  public Response removeFromCluserNodeLabels(Set<String> oldNodeLabels,
+      HttpServletRequest hsr) throws Exception {
+    // oldNodeLabels is specified inside hsr
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.POST,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.REMOVE_NODE_LABELS, null,
+        null);
+  }
+
+  @Override
+  public NodeLabelsInfo getLabelsOnNode(HttpServletRequest hsr, String nodeId)
+      throws IOException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        NodeLabelsInfo.class, HTTPMethods.GET, RMWSConsts.RM_WEB_SERVICE_PATH
+            + RMWSConsts.NODES + "/" + nodeId + "/get-labels",
+        null, null);
+  }
+
+  @Override
+  public AppPriority getAppPriority(HttpServletRequest hsr, String appId)
+      throws AuthorizationException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        AppPriority.class, HTTPMethods.GET, RMWSConsts.RM_WEB_SERVICE_PATH
+            + RMWSConsts.APPS + "/" + appId + "/" + RMWSConsts.PRIORITY,
+        null, null);
+  }
+
+  @Override
+  public Response updateApplicationPriority(AppPriority targetPriority,
+      HttpServletRequest hsr, String appId) throws AuthorizationException,
+      YarnException, InterruptedException, IOException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.PUT, RMWSConsts.RM_WEB_SERVICE_PATH
+            + RMWSConsts.APPS + "/" + appId + "/" + RMWSConsts.PRIORITY,
+        targetPriority, null);
+  }
+
+  @Override
+  public AppQueue getAppQueue(HttpServletRequest hsr, String appId)
+      throws AuthorizationException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        AppQueue.class, HTTPMethods.GET, RMWSConsts.RM_WEB_SERVICE_PATH
+            + RMWSConsts.APPS + "/" + appId + "/" + RMWSConsts.QUEUE,
+        null, null);
+  }
+
+  @Override
+  public Response updateAppQueue(AppQueue targetQueue, HttpServletRequest hsr,
+      String appId) throws AuthorizationException, YarnException,
+      InterruptedException, IOException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.PUT, RMWSConsts.RM_WEB_SERVICE_PATH
+            + RMWSConsts.APPS + "/" + appId + "/" + RMWSConsts.QUEUE,
+        targetQueue, null);
+  }
+
+  @Override
+  public Response createNewApplication(HttpServletRequest hsr)
+      throws AuthorizationException, IOException, InterruptedException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.POST,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.APPS_NEW_APPLICATION, null,
+        null);
+  }
+
+  @Override
+  public Response submitApplication(ApplicationSubmissionContextInfo newApp,
+      HttpServletRequest hsr)
+      throws AuthorizationException, IOException, InterruptedException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.POST,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.APPS, newApp, null);
+  }
+
+  @Override
+  public Response postDelegationToken(DelegationToken tokenData,
+      HttpServletRequest hsr) throws AuthorizationException, IOException,
+      InterruptedException, Exception {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.POST,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.DELEGATION_TOKEN, tokenData,
+        null);
+  }
+
+  @Override
+  public Response postDelegationTokenExpiration(HttpServletRequest hsr)
+      throws AuthorizationException, IOException, InterruptedException,
+      Exception {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.POST,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.DELEGATION_TOKEN_EXPIRATION,
+        null, null);
+  }
+
+  @Override
+  public Response cancelDelegationToken(HttpServletRequest hsr)
+      throws AuthorizationException, IOException, InterruptedException,
+      Exception {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.DELETE,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.DELEGATION_TOKEN, null,
+        null);
+  }
+
+  @Override
+  public Response createNewReservation(HttpServletRequest hsr)
+      throws AuthorizationException, IOException, InterruptedException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.POST,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.RESERVATION_NEW, null,
+        null);
+  }
+
+  @Override
+  public Response submitReservation(ReservationSubmissionRequestInfo resContext,
+      HttpServletRequest hsr)
+      throws AuthorizationException, IOException, InterruptedException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.POST,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.RESERVATION_SUBMIT,
+        resContext, null);
+  }
+
+  @Override
+  public Response updateReservation(ReservationUpdateRequestInfo resContext,
+      HttpServletRequest hsr)
+      throws AuthorizationException, IOException, InterruptedException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.POST,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.RESERVATION_UPDATE,
+        resContext, null);
+  }
+
+  @Override
+  public Response deleteReservation(ReservationDeleteRequestInfo resContext,
+      HttpServletRequest hsr)
+      throws AuthorizationException, IOException, InterruptedException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.POST,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.RESERVATION_DELETE,
+        resContext, null);
+  }
+
+  @Override
+  public Response listReservation(String queue, String reservationId,
+      long startTime, long endTime, boolean includeResourceAllocations,
+      HttpServletRequest hsr) throws Exception {
+    // queue, reservationId, startTime, endTime, includeResourceAllocations are
+    // specified inside hsr
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.RESERVATION_LIST, null,
+        null);
+  }
+
+  @Override
+  public AppTimeoutInfo getAppTimeout(HttpServletRequest hsr, String appId,
+      String type) throws AuthorizationException {
+    return RouterWebServiceUtil
+        .genericForward(webAppAddress, hsr, AppTimeoutInfo.class,
+            HTTPMethods.GET, RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.APPS
+                + "/" + appId + "/" + RMWSConsts.TIMEOUTS + "/" + type,
+            null, null);
+  }
+
+  @Override
+  public AppTimeoutsInfo getAppTimeouts(HttpServletRequest hsr, String appId)
+      throws AuthorizationException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        AppTimeoutsInfo.class, HTTPMethods.GET, RMWSConsts.RM_WEB_SERVICE_PATH
+            + RMWSConsts.APPS + "/" + appId + "/" + RMWSConsts.TIMEOUTS,
+        null, null);
+  }
+
+  @Override
+  public Response updateApplicationTimeout(AppTimeoutInfo appTimeout,
+      HttpServletRequest hsr, String appId) throws AuthorizationException,
+      YarnException, InterruptedException, IOException {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        Response.class, HTTPMethods.PUT, RMWSConsts.RM_WEB_SERVICE_PATH
+            + RMWSConsts.APPS + "/" + appId + "/" + RMWSConsts.TIMEOUT,
+        appTimeout, null);
+  }
+
+  @Override
+  public AppAttemptsInfo getAppAttempts(HttpServletRequest hsr, String appId) {
+    return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
+        AppAttemptsInfo.class, HTTPMethods.GET, RMWSConsts.RM_WEB_SERVICE_PATH
+            + RMWSConsts.APPS + "/" + appId + "/" + RMWSConsts.APPATTEMPTS,
+        null, null);
+  }
+
+  @Override
+  public AppAttemptInfo getAppAttempt(HttpServletRequest req,
+      HttpServletResponse res, String appId, String appAttemptId) {
+    return RouterWebServiceUtil.genericForward(webAppAddress, req,
+        AppAttemptInfo.class,
+        HTTPMethods.GET, RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.APPS + "/"
+            + appId + "/" + RMWSConsts.APPATTEMPTS + "/" + appAttemptId,
+        null, null);
+  }
+
+  @Override
+  public ContainersInfo getContainers(HttpServletRequest req,
+      HttpServletResponse res, String appId, String appAttemptId) {
+    return RouterWebServiceUtil.genericForward(webAppAddress, req,
+        ContainersInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.APPS + "/" + appId + "/"
+            + RMWSConsts.APPATTEMPTS + "/" + appAttemptId + "/"
+            + RMWSConsts.CONTAINERS,
+        null, null);
+  }
+
+  @Override
+  public ContainerInfo getContainer(HttpServletRequest req,
+      HttpServletResponse res, String appId, String appAttemptId,
+      String containerId) {
+    return RouterWebServiceUtil.genericForward(webAppAddress, req,
+        ContainerInfo.class, HTTPMethods.GET,
+        RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.APPS + "/" + appId + "/"
+            + RMWSConsts.APPATTEMPTS + "/" + appAttemptId + "/"
+            + RMWSConsts.CONTAINERS + "/" + containerId,
+        null, null);
+  }
+
+  @Override
+  public void setNextInterceptor(RESTRequestInterceptor next) {
+    throw new YarnRuntimeException("setNextInterceptor is being called on "
+        + "DefaultRequestInterceptorREST, which should be the last one "
+        + "in the chain. Check if the interceptor pipeline configuration "
+        + "is correct");
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/HTTPMethods.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/HTTPMethods.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/HTTPMethods.java
new file mode 100644
index 0000000..45056ca
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/HTTPMethods.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.yarn.server.router.webapp;
+
+/**
+ * HTTP verbs.
+ **/
+public enum HTTPMethods {
+
+  /* to retrieve resource representation/information */
+  GET,
+  /* to update existing resource */
+  PUT,
+  /* to delete resources */
+  DELETE,
+  /* to create new subordinate resources */
+  POST
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RESTRequestInterceptor.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RESTRequestInterceptor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RESTRequestInterceptor.java
new file mode 100644
index 0000000..06f39b5
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RESTRequestInterceptor.java
@@ -0,0 +1,125 @@
+/**
+ * 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.yarn.server.router.webapp;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.hadoop.conf.Configurable;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWebServiceProtocol;
+import org.apache.hadoop.yarn.server.webapp.WebServices;
+import org.apache.hadoop.yarn.server.webapp.dao.AppAttemptInfo;
+import org.apache.hadoop.yarn.server.webapp.dao.ContainerInfo;
+import org.apache.hadoop.yarn.server.webapp.dao.ContainersInfo;
+
+/**
+ * Defines the contract to be implemented by the request intercepter classes,
+ * that can be used to intercept and inspect messages sent from the client to
+ * the resource manager server.
+ *
+ * This class includes 4 methods getAppAttempts, getAppAttempt, getContainers
+ * and getContainer that belong to {@link WebServices}. They are in this class
+ * to make sure that RouterWebServices implements the same REST methods of
+ * {@code RMWebServices}.
+ */
+public interface RESTRequestInterceptor
+    extends RMWebServiceProtocol, Configurable {
+
+  /**
+   * This method is called for initializing the intercepter. This is guaranteed
+   * to be called only once in the lifetime of this instance.
+   *
+   * @param user the name of the client
+   */
+  void init(String user);
+
+  /**
+   * This method is called to release the resources held by the intercepter.
+   * This will be called when the application pipeline is being destroyed. The
+   * concrete implementations should dispose the resources and forward the
+   * request to the next intercepter, if any.
+   */
+  void shutdown();
+
+  /**
+   * Sets the next intercepter in the pipeline. The concrete implementation of
+   * this interface should always pass the request to the nextInterceptor after
+   * inspecting the message. The last intercepter in the chain is responsible to
+   * send the messages to the resource manager service and so the last
+   * intercepter will not receive this method call.
+   *
+   * @param nextInterceptor the RESTRequestInterceptor to set in the pipeline
+   */
+  void setNextInterceptor(RESTRequestInterceptor nextInterceptor);
+
+  /**
+   * Returns the next intercepter in the chain.
+   *
+   * @return the next intercepter in the chain
+   */
+  RESTRequestInterceptor getNextInterceptor();
+
+  /**
+   *
+   * @see WebServices#getAppAttempt(HttpServletRequest, HttpServletResponse,
+   *      String, String)
+   * @param req the servlet request
+   * @param res the servlet response
+   * @param appId the application we want to get the appAttempt. It is a
+   *          PathParam.
+   * @param appAttemptId the AppAttempt we want to get the info. It is a
+   *          PathParam.
+   * @return AppAttemptInfo of the specific AppAttempt
+   */
+  AppAttemptInfo getAppAttempt(HttpServletRequest req, HttpServletResponse res,
+      String appId, String appAttemptId);
+
+  /**
+   *
+   * @see WebServices#getContainers(HttpServletRequest, HttpServletResponse,
+   *      String, String)
+   * @param req the servlet request
+   * @param res the servlet response
+   * @param appId the application we want to get the containers info. It is a
+   *          PathParam.
+   * @param appAttemptId the AppAttempt we want to get the info. It is a
+   *          PathParam.
+   * @return ContainersInfo of all the containers that belong to the specific
+   *         AppAttempt
+   */
+  ContainersInfo getContainers(HttpServletRequest req, HttpServletResponse res,
+      String appId, String appAttemptId);
+
+  /**
+   *
+   * @see WebServices#getContainer(HttpServletRequest, HttpServletResponse,
+   *      String, String, String)
+   * @param req the servlet request
+   * @param res the servlet response
+   * @param appId the application we want to get the containers info. It is a
+   *          PathParam.
+   * @param appAttemptId the AppAttempt we want to get the info. It is a
+   *          PathParam.
+   * @param containerId the container we want to get the info. It is a
+   *          PathParam.
+   * @return ContainerInfo of the specific ContainerId
+   */
+  ContainerInfo getContainer(HttpServletRequest req, HttpServletResponse res,
+      String appId, String appAttemptId, String containerId);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterWebApp.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterWebApp.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterWebApp.java
new file mode 100644
index 0000000..5436bad
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterWebApp.java
@@ -0,0 +1,48 @@
+/**
+ * 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.yarn.server.router.webapp;
+
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.JAXBContextResolver;
+import org.apache.hadoop.yarn.server.router.Router;
+import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
+import org.apache.hadoop.yarn.webapp.WebApp;
+import org.apache.hadoop.yarn.webapp.YarnWebParams;
+
+/**
+ * The Router webapp.
+ */
+public class RouterWebApp extends WebApp implements YarnWebParams {
+  private Router router;
+
+  public RouterWebApp(Router router) {
+    this.router = router;
+  }
+
+  @Override
+  public void setup() {
+    bind(JAXBContextResolver.class);
+    bind(RouterWebServices.class);
+    bind(GenericExceptionHandler.class);
+    bind(RouterWebApp.class).toInstance(this);
+
+    if (router != null) {
+      bind(Router.class).toInstance(router);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/bfd967d3/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterWebServiceUtil.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterWebServiceUtil.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterWebServiceUtil.java
new file mode 100644
index 0000000..18618ee
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterWebServiceUtil.java
@@ -0,0 +1,227 @@
+/**
+ * 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.yarn.server.router.webapp;
+
+import java.io.IOException;
+import java.security.PrivilegedExceptionAction;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWebAppUtil;
+import org.apache.hadoop.yarn.webapp.BadRequestException;
+import org.apache.hadoop.yarn.webapp.ForbiddenException;
+import org.apache.hadoop.yarn.webapp.NotFoundException;
+
+import com.sun.jersey.api.ConflictException;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.WebResource.Builder;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+
+/**
+ * The Router webservice util class.
+ */
+public final class RouterWebServiceUtil {
+
+  private static String user = "YarnRouter";
+
+  private static final Log LOG =
+      LogFactory.getLog(RouterWebServiceUtil.class.getName());
+
+  /** Disable constructor. */
+  private RouterWebServiceUtil() {
+  }
+
+  /**
+   * Creates and performs a REST call to a specific WebService.
+   *
+   * @param webApp the address of the remote webap
+   * @param hsr the servlet request
+   * @param returnType the return type of the REST call
+   * @param <T> Type of return object.
+   * @param method the HTTP method of the REST call
+   * @param targetPath additional path to add to the webapp address
+   * @param formParam the form parameters as input for a specific REST call
+   * @param additionalParam the query parameters as input for a specific REST
+   *          call in case the call has no servlet request
+   * @return the retrieved entity from the REST call
+   */
+  protected static <T> T genericForward(String webApp, HttpServletRequest hsr,
+      final Class<T> returnType, HTTPMethods method, String targetPath,
+      Object formParam, Map<String, String[]> additionalParam) {
+
+    UserGroupInformation callerUGI = null;
+
+    if (hsr != null) {
+      callerUGI = RMWebAppUtil.getCallerUserGroupInformation(hsr, true);
+    } else {
+      // user not required
+      callerUGI = UserGroupInformation.createRemoteUser(user);
+
+    }
+
+    if (callerUGI == null) {
+      LOG.error("Unable to obtain user name, user not authenticated");
+      return null;
+    }
+
+    try {
+      return callerUGI.doAs(new PrivilegedExceptionAction<T>() {
+        @SuppressWarnings("unchecked")
+        @Override
+        public T run() {
+
+          Map<String, String[]> paramMap = null;
+
+          // We can have hsr or additionalParam. There are no case with both.
+          if (hsr != null) {
+            paramMap = hsr.getParameterMap();
+          } else if (additionalParam != null) {
+            paramMap = additionalParam;
+          }
+
+          ClientResponse response = RouterWebServiceUtil.invokeRMWebService(
+              webApp, targetPath, method,
+              (hsr == null) ? null : hsr.getPathInfo(), paramMap, formParam);
+          if (Response.class.equals(returnType)) {
+            return (T) RouterWebServiceUtil.clientResponseToResponse(response);
+          }
+          // YARN RM can answer with Status.OK or it throws an exception
+          if (response.getStatus() == 200) {
+            return response.getEntity(returnType);
+          }
+          RouterWebServiceUtil.retrieveException(response);
+          return null;
+        }
+      });
+    } catch (InterruptedException e) {
+      return null;
+    } catch (IOException e) {
+      return null;
+    }
+  }
+
+  /**
+   * Performs an invocation of a REST call on a remote RMWebService.
+   *
+   * @param additionalParam
+   */
+  private static ClientResponse invokeRMWebService(String webApp, String path,
+      HTTPMethods method, String additionalPath,
+      Map<String, String[]> queryParams, Object formParam) {
+    Client client = Client.create();
+
+    WebResource webResource = client.resource(webApp).path(path);
+
+    if (additionalPath != null && !additionalPath.isEmpty()) {
+      webResource = webResource.path(additionalPath);
+    }
+
+    if (queryParams != null && !queryParams.isEmpty()) {
+      MultivaluedMap<String, String> paramMap = new MultivaluedMapImpl();
+
+      for (Entry<String, String[]> param : queryParams.entrySet()) {
+        String[] values = param.getValue();
+        for (int i = 0; i < values.length; i++) {
+          paramMap.add(param.getKey(), values[i]);
+        }
+      }
+      webResource = webResource.queryParams(paramMap);
+    }
+
+    // I can forward the call in JSON or XML since the Router will convert it
+    // again in Object before send it back to the client
+    Builder builder = null;
+    if (formParam != null) {
+      builder = webResource.entity(formParam, MediaType.APPLICATION_XML);
+      builder = builder.accept(MediaType.APPLICATION_XML);
+    } else {
+      builder = webResource.accept(MediaType.APPLICATION_XML);
+    }
+
+    ClientResponse response = null;
+
+    switch (method) {
+    case DELETE:
+      response = builder.delete(ClientResponse.class);
+      break;
+    case GET:
+      response = builder.get(ClientResponse.class);
+      break;
+    case POST:
+      response = builder.post(ClientResponse.class);
+      break;
+    case PUT:
+      response = builder.put(ClientResponse.class);
+      break;
+    default:
+      break;
+    }
+
+    return response;
+  }
+
+  public static Response clientResponseToResponse(ClientResponse r) {
+    if (r == null) {
+      return null;
+    }
+    // copy the status code
+    ResponseBuilder rb = Response.status(r.getStatus());
+    // copy all the headers
+    for (Entry<String, List<String>> entry : r.getHeaders().entrySet()) {
+      for (String value : entry.getValue()) {
+        rb.header(entry.getKey(), value);
+      }
+    }
+    // copy the entity
+    rb.entity(r.getEntityInputStream());
+    // return the response
+    return rb.build();
+  }
+
+  public static void retrieveException(ClientResponse response) {
+    String serverErrorMsg = response.getEntity(String.class);
+    int status = response.getStatus();
+    if (status == 400) {
+      throw new BadRequestException(serverErrorMsg);
+    }
+    if (status == 403) {
+      throw new ForbiddenException(serverErrorMsg);
+    }
+    if (status == 404) {
+      throw new NotFoundException(serverErrorMsg);
+    }
+    if (status == 409) {
+      throw new ConflictException(serverErrorMsg);
+    }
+
+  }
+
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org