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 bi...@apache.org on 2019/03/29 20:55:19 UTC

[hadoop] 01/02: YARN-7129. Application Catalog for YARN applications. Contributed by Eric Yang

This is an automated email from the ASF dual-hosted git repository.

billie pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/hadoop.git

commit 7ee32a2eb187d43f1c8d7c6416eebc13d461ee1e
Author: Billie Rinaldi <bi...@apache.org>
AuthorDate: Fri Mar 29 07:42:58 2019 -0700

    YARN-7129. Application Catalog for YARN applications. Contributed by Eric Yang
---
 hadoop-project/pom.xml                             |   48 +-
 .../hadoop-yarn-applications-catalog/README.md     |   50 +
 .../Dockerfile                                     |   37 +
 .../README.md                                      |   43 +
 .../pom.xml                                        |  108 ++
 .../src/main/resources/jaas.config                 |    9 +
 .../src/main/resources/samples.xml                 |  135 ++
 .../src/main/scripts/entrypoint.sh                 |   45 +
 .../src/main/scripts/setup-image.sh                |   21 +
 .../.gitignore                                     |    3 +
 .../.yarnrc                                        |    1 +
 .../README.md                                      |   51 +
 .../dev-support/findbugs-exclude.xml               |   20 +
 .../package.json                                   |   40 +
 .../pom.xml                                        |  455 ++++++
 .../yarn/appcatalog/application/AppCatalog.java    |   60 +
 .../application/AppCatalogSolrClient.java          |  359 +++++
 .../appcatalog/application/YarnServiceClient.java  |  174 +++
 .../yarn/appcatalog/application/package-info.java  |   22 +
 .../controller/AppDetailsController.java           |  265 ++++
 .../appcatalog/controller/AppListController.java   |  182 +++
 .../appcatalog/controller/AppStoreController.java  |  198 +++
 .../yarn/appcatalog/controller/package-info.java   |   22 +
 .../hadoop/yarn/appcatalog/model/AppDetails.java   |   76 +
 .../hadoop/yarn/appcatalog/model/AppEntry.java     |   72 +
 .../yarn/appcatalog/model/AppStoreEntry.java       |  106 ++
 .../hadoop/yarn/appcatalog/model/Application.java  |   67 +
 .../hadoop/yarn/appcatalog/model/package-info.java |   22 +
 .../hadoop/yarn/appcatalog/utils/RandomWord.java   |  422 ++++++
 .../yarn/appcatalog/utils/WordLengthException.java |   29 +
 .../hadoop/yarn/appcatalog/utils/package-info.java |   22 +
 .../src/main/javascript/app.js                     |   59 +
 .../src/main/javascript/controllers.js             |  320 +++++
 .../src/main/javascript/filters.js                 |   32 +
 .../src/main/javascript/routes.js                  |   17 +
 .../src/main/javascript/services.js                |   17 +
 .../src/main/resources/appcatalog.properties       |    1 +
 .../src/main/resources/log4j.properties            |   23 +
 .../src/main/webapp/.gitignore                     |    1 +
 .../src/main/webapp/WEB-INF/beans.xml              |   22 +
 .../src/main/webapp/WEB-INF/web.xml                |   75 +
 .../src/main/webapp/css/bootstrap-hadoop.css       | 1488 ++++++++++++++++++++
 .../src/main/webapp/css/bootstrap-hadoop.min.css   |   18 +
 .../src/main/webapp/css/img/feather.png            |  Bin 0 -> 6066 bytes
 .../src/main/webapp/css/img/jenkins.png            |  Bin 0 -> 23140 bytes
 .../src/main/webapp/css/img/loading.svg            |    8 +
 .../pattern-f61c2e99f82389a67432f54155c5f483.png   |  Bin 0 -> 27786 bytes
 .../src/main/webapp/css/specific.css               |  252 ++++
 .../src/main/webapp/css/theme.css                  |   30 +
 .../src/main/webapp/index.html                     |   82 ++
 .../src/main/webapp/js/bootstrap-hadoop.js         |  284 ++++
 .../src/main/webapp/js/bootstrap-hadoop.min.js     |   19 +
 .../src/main/webapp/partials/deploy.html           |   80 ++
 .../src/main/webapp/partials/details.html          |   64 +
 .../src/main/webapp/partials/home.html             |   52 +
 .../src/main/webapp/partials/new.html              |  111 ++
 .../src/main/webapp/theme.html                     |  649 +++++++++
 .../application/EmbeddedSolrServerFactory.java     |  104 ++
 .../application/TestAppCatalogSolrClient.java      |  112 ++
 .../controller/AppDetailsControllerTest.java       |  138 ++
 .../controller/AppListControllerTest.java          |   95 ++
 .../controller/AppStoreControllerTest.java         |   97 ++
 .../src/test/javascript/controllersSpec.js         |  249 ++++
 .../src/test/javascript/karma.conf.js              |   34 +
 .../src/test/resources/configsets.tgz              |  Bin 0 -> 2996 bytes
 .../exampleCollection/conf/lang/stopwords_en.txt   |   54 +
 .../configsets/exampleCollection/conf/params.json  |   20 +
 .../exampleCollection/conf/protwords.txt           |   20 +
 .../configsets/exampleCollection/conf/schema.xml   |  115 ++
 .../exampleCollection/conf/solrconfig.xml          |   36 +
 .../exampleCollection/conf/stopwords.txt           |   14 +
 .../configsets/exampleCollection/conf/synonyms.txt |   28 +
 .../src/test/resources/log4j.properties            |   11 +
 .../hadoop-yarn-applications-catalog/pom.xml       |   37 +
 .../yarn/service/client/ApiServiceClient.java      |   13 +-
 .../examples/appcatalog/appcatalog.json            |   28 +
 .../hadoop-yarn/hadoop-yarn-applications/pom.xml   |    1 +
 .../src/site/markdown/yarn-service/Examples.md     |   13 +
 78 files changed, 8083 insertions(+), 4 deletions(-)

diff --git a/hadoop-project/pom.xml b/hadoop-project/pom.xml
index a5af081..7bd012d 100644
--- a/hadoop-project/pom.xml
+++ b/hadoop-project/pom.xml
@@ -147,7 +147,13 @@
     <surefire.fork.timeout>900</surefire.fork.timeout>
     <aws-java-sdk.version>1.11.375</aws-java-sdk.version>
     <hsqldb.version>2.3.4</hsqldb.version>
-    <frontend-maven-plugin.version>1.5</frontend-maven-plugin.version>
+    <frontend-maven-plugin.version>1.6</frontend-maven-plugin.version>
+    <maven-dependency-plugin.version>3.0.1</maven-dependency-plugin.version>
+    <jasmine-maven-plugin.version>2.1</jasmine-maven-plugin.version>
+    <phantomjs-maven-plugin.version>0.7</phantomjs-maven-plugin.version>
+    <yuicompressor-maven-plugin.version>1.5.1</yuicompressor-maven-plugin.version>
+    <maven-project-info-reports-plugin.version>2.9</maven-project-info-reports-plugin.version>
+
     <!-- the version of Hadoop declared in the version resources; can be overridden
     so that Hadoop 3.x can declare itself a 2.x artifact. -->
     <declared.hadoop.version>${hadoop.version}</declared.hadoop.version>
@@ -161,6 +167,8 @@
     <junit.vintage.version>5.3.1</junit.vintage.version>
     <junit.platform.version>1.3.1</junit.platform.version>
     <jline.version>3.9.0</jline.version>
+    <powermock.version>1.5.6</powermock.version>
+    <solr.version>7.7.0</solr.version>
   </properties>
 
   <dependencyManagement>
@@ -467,6 +475,19 @@
 
       <dependency>
         <groupId>org.apache.hadoop</groupId>
+        <artifactId>hadoop-yarn-services-api</artifactId>
+        <version>${hadoop.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>org.apache.hadoop</groupId>
+        <artifactId>hadoop-yarn-applications-catalog-webapp</artifactId>
+        <version>${hadoop.version}</version>
+        <type>war</type>
+      </dependency>
+
+      <dependency>
+        <groupId>org.apache.hadoop</groupId>
          <artifactId>hadoop-mapreduce-client-jobclient</artifactId>
         <version>${hadoop.version}</version>
         <type>test-jar</type>
@@ -1651,6 +1672,31 @@
           <artifactId>hadoop-maven-plugins</artifactId>
           <version>${hadoop.version}</version>
         </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-dependency-plugin</artifactId>
+          <version>${maven-dependency-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>net.alchim31.maven</groupId>
+          <artifactId>yuicompressor-maven-plugin</artifactId>
+          <version>${yuicompressor-maven-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>com.github.klieber</groupId>
+          <artifactId>phantomjs-maven-plugin</artifactId>
+          <version>${phantomjs-maven-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>com.github.searls</groupId>
+          <artifactId>jasmine-maven-plugin</artifactId>
+          <version>${jasmine-maven-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>com.github.eirslett</groupId>
+          <artifactId>frontend-maven-plugin</artifactId>
+          <version>${frontend-maven-plugin.version}</version>
+        </plugin>
       </plugins>
     </pluginManagement>
 
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/README.md b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/README.md
new file mode 100644
index 0000000..f048661
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/README.md
@@ -0,0 +1,50 @@
+<!--
+   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.
+-->
+# Apache Hadoop YARN Application Catalog
+
+## Introduction
+
+YARN Application Catalog is application catalog for
+deploying docker enabled cloud application on Hadoop.
+
+check it out:
+
+```bash
+git clone https://github.com/apache/hadoop.git
+```
+
+## Prerequisites
+* Firefox or Chrome
+* [npm](https://www.npmjs.org)
+* [nodejs](http://nodejs.org)
+* [JDK](http://www.oracle.com/technetwork/java/javaee/downloads/index.html)
+* [IDE](http://www.jetbrains.com/)
+* [bower](http://bower.io)
+* [PhantomJs](http://phantomjs.org) or `brew install phantomjs`
+* [Docker](http://docker.io)
+
+## Installation
+
+```bash
+mvn package
+```
+
+When running this command a couple of things happen:
+* YARN Application Catalog web application is built
+* YARN Application Docker image is built
+
+## Status of the project
+
+See Apache [JIRA](http://issues.apache.org/jira/browse/HADOOP)
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/Dockerfile b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/Dockerfile
new file mode 100644
index 0000000..4a3ec65
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/Dockerfile
@@ -0,0 +1,37 @@
+# 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.
+
+FROM centos:7
+
+RUN yum -y install tomcat lsof krb5-workstation sssd-client curl
+SHELL ["/bin/bash", "-o", "pipefail", "-c"]
+RUN mkdir -p /opt/apache/solr && \
+    curl -SL http://archive.apache.org/dist/lucene/solr/7.7.0/solr-7.7.0.tgz | \
+    tar -xzC /opt/apache/solr --strip 1
+COPY src/main/scripts/setup-image.sh /setup-image.sh
+COPY src/main/resources/samples.xml /tmp/samples.xml
+COPY src/main/resources/jaas.config /etc/tomcat/jaas.config.template
+COPY src/main/scripts/entrypoint.sh /usr/bin/entrypoint.sh
+COPY target/ROOT.war /var/lib/tomcat/webapps/ROOT.war
+RUN chmod 755 /setup-image.sh
+RUN chmod 755 /usr/bin/entrypoint.sh
+RUN /setup-image.sh
+
+EXPOSE 8080
+EXPOSE 8983
+WORKDIR /
+
+ENTRYPOINT ["/usr/bin/entrypoint.sh" ]
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/README.md b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/README.md
new file mode 100644
index 0000000..1e2d12b
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/README.md
@@ -0,0 +1,43 @@
+<!---
+  Licensed 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. See accompanying LICENSE file.
+-->
+# Apache Hadoop YARN AppCatalog Docker Image
+
+## Introduction
+
+AppCatalog Docker image is pre-packaged docker container for Hadoop Application Catalog.
+
+check it out:
+
+```
+git clone https://github.com/apache/hadoop.git
+```
+
+## Compile
+
+```
+mvn package
+```
+
+## Run
+
+```
+docker run -d -p 8080:8080 -p 8983:8983 hadoop/appcatalog-docker:1.0-SNAPSHOT
+```
+
+When running this command a couple of things happens:
+* Solr server will create appcatalog collection for hosting application catalog
+* Sample applications are registered in Embedded Solr
+* Tomcat will run appcatalog-webapp on port 8080
+
+User can browse port 8080 to deploy application on a Hadoop cluster.
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/pom.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/pom.xml
new file mode 100644
index 0000000..7c0d3ef
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/pom.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.hadoop</groupId>
+  <artifactId>hadoop-yarn-applications-catalog-docker</artifactId>
+  <packaging>pom</packaging>
+
+  <parent>
+    <artifactId>hadoop-yarn-applications-catalog</artifactId>
+    <groupId>org.apache.hadoop</groupId>
+    <version>3.3.0-SNAPSHOT</version>
+  </parent>
+
+  <name>YARN Application Catalog Docker Image</name>
+  <url>http://maven.apache.org</url>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-yarn-applications-catalog-webapp</artifactId>
+      <version>${project.version}</version>
+      <type>war</type>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>src/main/resources/jaas.config</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>docker</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-dependency-plugin</artifactId>
+            <version>3.0.1</version>
+            <executions>
+              <execution>
+                <id>copy-dependencies</id>
+                <phase>package</phase>
+                <goals>
+                  <goal>copy</goal>
+                </goals>
+                <configuration>
+                  <artifactItems>
+                    <artifactItem>
+                      <groupId>org.apache.hadoop</groupId>
+                      <artifactId>hadoop-yarn-applications-catalog-webapp</artifactId>
+                      <version>${project.version}</version>
+                      <destFileName>ROOT.war</destFileName>
+                      <type>war</type>
+                    </artifactItem>
+                  </artifactItems>
+                  <outputDirectory>${project.build.directory}</outputDirectory>
+                  <overWriteReleases>false</overWriteReleases>
+                  <overWriteSnapshots>true</overWriteSnapshots>
+                  <excludeTransitive>true</excludeTransitive>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>com.spotify</groupId>
+            <artifactId>dockerfile-maven-plugin</artifactId>
+            <version>1.3.4</version>
+            <executions>
+              <execution>
+                <id>default</id>
+                <goals>
+                  <goal>build</goal>
+                </goals>
+              </execution>
+            </executions>
+            <configuration>
+              <repository>apache/hadoop-yarn-applications-catalog-docker</repository>
+              <tag>${project.version}</tag>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/src/main/resources/jaas.config b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/src/main/resources/jaas.config
new file mode 100644
index 0000000..937df57
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/src/main/resources/jaas.config
@@ -0,0 +1,9 @@
+com.sun.security.jgss.krb5.initiate {
+  com.sun.security.auth.module.Krb5LoginModule required
+  doNotPrompt=true
+  principal="${PRINCIPAL}"
+  useKeyTab=true
+  keyTab="${KEYTAB}"
+  storeKey=true
+  useTicketCache=false;
+};
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/src/main/resources/samples.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/src/main/resources/samples.xml
new file mode 100644
index 0000000..5389cfb
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/src/main/resources/samples.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+-->
+<add>
+  <doc>
+    <field name="id">appStore_1</field>
+    <field name="type_s">AppStoreEntry</field>
+    <field name="org_s">Apache</field>
+    <field name="name_s">Http Server Project</field>
+    <field name="desc_s">The Number One HTTP Server On The Internet</field>
+    <field name="like_i">50000</field>
+    <field name="download_i">100000</field>
+    <field name="yarnfile_s">{
+  "name": "httpd",
+  "version": "1.0",
+  "components" :
+  [
+    {
+      "name": "httpd",
+      "number_of_containers": 2,
+      "artifact": {
+        "id": "centos/httpd-24-centos7:latest",
+        "type": "DOCKER"
+      },
+      "resource": {
+        "cpus": 1,
+        "memory": "256"
+      },
+      "configuration": {
+        "env": {
+          "YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE":"true",
+          "YARN_CONTAINER_RUNTIME_DOCKER_PORTS_MAPPING":"8080:8080"
+        },
+        "properties": {
+        }
+      }
+    }
+  ],
+  "quicklinks": {
+    "Httpd UI": "http://httpd.${SERVICE_NAME}.${USER}.${DOMAIN}:8080/"
+  }
+}
+    </field>
+  </doc>
+  <doc>
+    <field name="id">appStore_2</field>
+    <field name="type_s">AppStoreEntry</field>
+    <field name="org_s">Jenkins-ci.org</field>
+    <field name="name_s">Jenkins</field>
+    <field name="desc_s">The leading open source automation server</field>
+    <field name="like_i">100000</field>
+    <field name="download_i">1000000</field>
+    <field name="yarnfile_s">{
+  "name": "httpd",
+  "version": "1.0",
+  "components" :
+  [
+    {
+      "name": "jenkins",
+      "number_of_containers": 1,
+      "artifact": {
+        "id": "jenkins/jenkins:latest",
+        "type": "DOCKER"
+      },
+      "resource": {
+        "cpus": 1,
+        "memory": "1024"
+      },
+      "run_privileged_container": true,
+      "configuration": {
+        "env": {
+          "YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE":"true",
+          "YARN_CONTAINER_RUNTIME_DOCKER_PORTS_MAPPING":"8080:8080"
+        },
+        "properties": {
+        }
+      }
+    }
+  ],
+  "quicklinks": {
+    "Jenkins UI": "http://jenkins.${SERVICE_NAME}.${USER}.${DOMAIN}:8080/"
+  }
+}
+    </field>
+  </doc>
+  <doc>
+    <field name="id">appStore_3</field>
+    <field name="type_s">AppStoreEntry</field>
+    <field name="org_s">Docker</field>
+    <field name="name_s">Registry</field>
+    <field name="desc_s">The Docker Registry 2.0 implementation for storing and distributing Docker images.</field>
+    <field name="like_i">360</field>
+    <field name="download_i">1</field>
+    <field name="yarnfile_s">{
+  "name": "docker-registry",
+  "version": "1.0",
+  "components" :
+  [
+    {
+      "name": "registry",
+      "number_of_containers": 1,
+      "artifact": {
+        "id": "registry:latest",
+        "type": "DOCKER"
+      },
+      "resource": {
+        "cpus": 1,
+        "memory": "1024"
+      },
+      "configuration": {
+        "env": {
+          "YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE":"true",
+          "YARN_CONTAINER_RUNTIME_DOCKER_PORTS_MAPPING":"5000:5000"
+        },
+        "properties": {
+        }
+      }
+    }
+  ]
+}
+    </field>
+  </doc>
+</add>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/src/main/scripts/entrypoint.sh b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/src/main/scripts/entrypoint.sh
new file mode 100755
index 0000000..1666063
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/src/main/scripts/entrypoint.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+# 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.
+
+template_generator() {
+  REGEX='(\$\{[a-zA-Z_][a-zA-Z_0-9]*\})'
+  if [ -e "$2" ]; then
+    mv -f "$2" "$2.bak"
+  fi
+  while IFS='' read -r line || [[ -n "$line" ]]; do
+    while [[ "$line" =~ $REGEX ]] ; do
+      LHS=${BASH_REMATCH[1]}
+      RHS="$(eval echo "\"$LHS\"")"
+      line=${line//$LHS/$RHS}
+    done
+    echo "$line" >> "$2"
+  done < "$1"
+}
+
+export JAVA_HOME=/usr/lib/jvm/jre
+export HADOOP_CONF_DIR=/etc/hadoop/conf
+/opt/apache/solr/bin/solr start -p 8983 -force
+/opt/apache/solr/bin/solr create_core -c appcatalog -force
+/opt/apache/solr/bin/post -c appcatalog /tmp/samples.xml
+if [ -d /etc/hadoop/conf ]; then
+  sed -i.bak 's/shared.loader=.*$/shared.loader=\/etc\/hadoop\/conf/g' /etc/tomcat/catalina.properties
+fi
+if [ -e "$KEYTAB" ]; then
+  export JAVA_OPTS="$JAVA_OPTS -Djava.security.auth.login.config=/etc/tomcat/jaas.config -Djava.security.krb5.conf=/etc/krb5.conf -Djavax.security.auth.useSubjectCredsOnly=false"
+  template_generator /etc/tomcat/jaas.config.template /etc/tomcat/jaas.config
+fi
+/usr/libexec/tomcat/server start
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/src/main/scripts/setup-image.sh b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/src/main/scripts/setup-image.sh
new file mode 100755
index 0000000..c9376f9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-docker/src/main/scripts/setup-image.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# 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.
+
+mkdir -p /etc/hadoop
+mkdir -p /opt/apache/solr/server/logs
+chmod -R 777 /opt/apache/solr/server/logs /var/log/tomcat /var/cache/tomcat /var/lib/tomcat/webapps /opt/apache/solr/server/solr
+chmod 777 /etc/tomcat
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/.gitignore b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/.gitignore
new file mode 100644
index 0000000..a82f945
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/.gitignore
@@ -0,0 +1,3 @@
+.classpath
+.project
+/target/
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/.yarnrc b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/.yarnrc
new file mode 100644
index 0000000..e0ca4e9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/.yarnrc
@@ -0,0 +1 @@
+--modules-folder target/generated-sources/vendor
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/README.md b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/README.md
new file mode 100644
index 0000000..58fe29f
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/README.md
@@ -0,0 +1,51 @@
+<!---
+  Licensed 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. See accompanying LICENSE file.
+-->
+# Apache Hadoop YARN Application Catalog
+
+## Introduction
+
+Hadoop YARN Application Catalog is application catalog for
+deploying docker enabled cloud application on Hadoop.
+
+check it out:
+
+```bash
+git clone https://github.com/apache/hadoop.git
+```
+
+## Prerequisites
+* Firefox or Chrome
+* [npm](https://www.npmjs.org)
+* [nodejs](http://nodejs.org)
+* [JDK](http://www.oracle.com/technetwork/java/javaee/downloads/index.html)
+* [IDE](http://www.jetbrains.com/)
+* [bower](http://bower.io)
+* [PhantomJs](http://phantomjs.org) or `brew install phantomjs`
+* [Application Server](https://glassfish.java.net/download.html) or `brew install glassfish`
+
+## Installation
+
+```bash
+mvn package
+```
+
+When running this command a couple of things happen:
+* Npm and yarnpkg install will be run
+* JSLint will be run in src/main/javascript sources
+* Javascript will be minified
+* All the other standard maven phases.
+
+## Status of the project
+
+See Apache [JIRA](http://issues.apache.org/jira/browse/YARN)
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/dev-support/findbugs-exclude.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/dev-support/findbugs-exclude.xml
new file mode 100644
index 0000000..b89146a
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/dev-support/findbugs-exclude.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+-->
+<FindBugsFilter>
+
+</FindBugsFilter>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/package.json b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/package.json
new file mode 100644
index 0000000..e8781e0
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/package.json
@@ -0,0 +1,40 @@
+{
+    "name": "AppCatalog",
+    "private": true,
+    "version": "0.0.0",
+    "description": "YARN App Catalog",
+    "repository": "git://git.apache.org/hadoop.git",
+    "license": "Apache 2.0",
+    "dependencies": {
+        "jquery": "3.3.1",
+        "angular-loader": "~1.6.4",
+        "angular-mocks": "~1.6.4",
+        "angular-route": "~1.6.4",
+        "angular": "~1.6.4",
+        "bootstrap": "~3.3.7",
+        "roboto-fontface": "0.10.0"
+    },
+    "devDependencies": {
+        "http-server": "^0.6.1",
+        "requirejs": "^2.1.0",
+        "karma": "4.0.0",
+        "karma-requirejs": "^0.2.2",
+        "karma-script-launcher": "^0.1.0",
+        "karma-chrome-launcher": "^0.1.4",
+        "karma-firefox-launcher": "^0.1.3",
+        "karma-jasmine": "^0.1.5",
+        "karma-junit-reporter": "^0.2.2",
+        "shelljs": "^0.2.6",
+        "apidoc": "0.17.7"
+    },
+    "scripts": {
+        "prestart": "npm install & mvn clean package",
+        "start": "http-server target/app -a localhost -p 8000",
+        "pretest": "npm install",
+        "test": "karma start src/test/javascript/karma.conf.js",
+        "test-single-run": "karma start src/test/javascript/karma.conf.js  --single-run",
+        "preupdate-webdriver": "npm install",
+        "update-webdriver": "webdriver-manager update",
+        "update-index-async": "node -e \"require('shelljs/global'); sed('-i', /\\/\\/@@NG_LOADER_START@@[\\s\\S]*\\/\\/@@NG_LOADER_END@@/, '//@@NG_LOADER_START@@\\n' + cat('src/main/webapp/vendor/angular-loader/angular-loader.min.js') + '\\n//@@NG_LOADER_END@@', 'src/main/webapp/index.html');\""
+    }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/pom.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/pom.xml
new file mode 100644
index 0000000..8e0cae7
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/pom.xml
@@ -0,0 +1,455 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+-->
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.hadoop</groupId>
+  <artifactId>hadoop-yarn-applications-catalog-webapp</artifactId>
+  <packaging>war</packaging>
+
+  <parent>
+    <artifactId>hadoop-yarn-applications-catalog</artifactId>
+    <groupId>org.apache.hadoop</groupId>
+    <version>3.3.0-SNAPSHOT</version>
+  </parent>
+
+  <name>YARN Application Catalog Webapp</name>
+
+  <url>http://hadoop.apache.org</url>
+
+    <properties>
+        <artifact.name>app</artifact.name>
+        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
+        <vendor.loc>target/generated-sources/vendor</vendor.loc>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <dependency.locations.enabled>false</dependency.locations.enabled>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+          <groupId>io.swagger</groupId>
+          <artifactId>swagger-annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.9.5</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-module-junit4</artifactId>
+            <version>${powermock.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-mockito</artifactId>
+            <version>${powermock.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.mockito</groupId>
+                    <artifactId>mockito-all</artifactId>
+                </exclusion>
+            </exclusions>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-json-jackson</artifactId>
+            <version>2.12</version>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.javassist</groupId>
+                    <artifactId>javassist</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.fasterxml.jackson.jaxrs</groupId>
+                    <artifactId>jackson-jaxrs-base</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-json</artifactId>
+            <version>${jersey.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.solr</groupId>
+            <artifactId>solr-solrj</artifactId>
+            <version>${solr.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>jcl-over-slf4j</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.solr</groupId>
+            <artifactId>solr-core</artifactId>
+            <version>${solr.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>jcl-over-slf4j</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-io</artifactId>
+                </exclusion>
+            </exclusions>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.solr</groupId>
+            <artifactId>solr-test-framework</artifactId>
+            <version>${solr.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>jcl-over-slf4j</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-io</artifactId>
+                </exclusion>
+            </exclusions>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jcl-over-slf4j</artifactId>
+            <version>${slf4j.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>${slf4j.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.hadoop</groupId>
+            <artifactId>hadoop-common</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.hadoop</groupId>
+            <artifactId>hadoop-auth</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.hadoop</groupId>
+            <artifactId>hadoop-yarn-common</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.hadoop</groupId>
+            <artifactId>hadoop-yarn-services-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.hadoop</groupId>
+            <artifactId>hadoop-yarn-services-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>${jackson2.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+            <version>${jackson2.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>${jackson2.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.jaxrs</groupId>
+            <artifactId>jackson-jaxrs-json-provider</artifactId>
+            <version>${jackson2.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.jaxrs</groupId>
+            <artifactId>jackson-jaxrs-base</artifactId>
+            <version>${jackson2.version}</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <finalName>${artifact.name}</finalName>
+        <resources>
+            <resource>
+                <directory>src/main/javascript</directory>
+                <filtering>true</filtering>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>com.github.eirslett</groupId>
+                <artifactId>frontend-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>install node and yarn</id>
+                        <goals>
+                            <goal>install-node-and-yarn</goal>
+                        </goals>
+                        <phase>generate-resources</phase>
+                        <configuration>
+                            <nodeVersion>v8.11.3</nodeVersion>
+                            <yarnVersion>v1.7.0</yarnVersion>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>yarn install</id>
+                        <goals>
+                            <goal>yarn</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                    <compilerArguments>
+                        <endorseddirs>${endorsed.dir}</endorseddirs>
+                    </compilerArguments>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <systemPropertyVariables>
+                        <log4j.configuration>file:${project.build.testOutputDirectory}/log4j.properties</log4j.configuration>
+                    </systemPropertyVariables>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <webResources>
+                        <resource>
+                            <directory>target/generated-sources</directory>
+                            <includes>
+                                <include>vendor/jquery/**</include>
+                                <include>vendor/angular/**</include>
+                                <include>vendor/angular-route/**</include>
+                                <include>vendor/bootstrap/**</include>
+                                <include>vendor/roboto-fontface/fonts/roboto/Roboto-Regular.woff</include>
+                            </includes>
+                        </resource>
+                    </webResources>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>validate</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${endorsed.dir}</outputDirectory>
+                            <silent>true</silent>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>javax</groupId>
+                                    <artifactId>javaee-endorsed-api</artifactId>
+                                    <version>7.0</version>
+                                    <type>jar</type>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>net.alchim31.maven</groupId>
+                <artifactId>yuicompressor-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>compress-js</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <!--<goal>jslint</goal>-->
+                            <goal>compress</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <failOnWarning>true</failOnWarning>
+                    <!--<outputDirectory>src/main/webapp/js</outputDirectory>-->
+                    <outputDirectory>target/${artifact.name}/js</outputDirectory>
+                    <nosuffix>true</nosuffix>
+                    <excludes>
+                        <exclude>**/js/**/*js</exclude>
+                        <exclude>vendor/**</exclude>
+                        <exclude>**/*min.css</exclude>
+                        <exclude>**/*min.js</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>com.github.klieber</groupId>
+                <artifactId>phantomjs-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>install</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <version>2.1.1</version>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>com.github.searls</groupId>
+                <artifactId>jasmine-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test</goal>
+                            <goal>bdd</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <webDriverClassName>org.openqa.selenium.phantomjs.PhantomJSDriver</webDriverClassName>
+                    <webDriverCapabilities>
+                        <capability>
+                            <name>phantomjs.binary.path</name>
+                            <value>${phantomjs.binary}</value>
+                        </capability>
+                    </webDriverCapabilities>
+                    <preloadSources>
+                        <source>${vendor.loc}/jquery/dist/jquery.js</source>
+                        <source>${vendor.loc}/angular/angular.min.js</source>
+                        <source>${vendor.loc}/angular-route/angular-route.min.js</source>
+                        <source>${vendor.loc}/angular-mocks/angular-mocks.js</source>
+                    </preloadSources>
+                    <jsSrcDir>src/main/javascript</jsSrcDir>
+                    <jsTestSrcDir>src/test/javascript</jsTestSrcDir>
+                    <specIncludes>
+                        <include>*Spec.js</include>
+                    </specIncludes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>src/main/webapp/vendor/**</exclude>
+                        <exclude>src/main/resources/appcatalog.properties</exclude>
+                        <exclude>src/main/webapp//**/*.svg</exclude>
+                        <exclude>src/test/javascript/karma.conf.js</exclude>
+                        <exclude>src/test/resources/configsets/exampleCollection/conf/params.json</exclude>
+                        <exclude>src/test/resources/log4j.properties</exclude>
+                        <exclude>src/test/resources/jaas.config</exclude>
+                        <exclude>.bowerrc</exclude>
+                        <exclude>.yarnrc</exclude>
+                        <exclude>bower.json</exclude>
+                        <exclude>package.json</exclude>
+                        <exclude>yarn.lock</exclude>
+                        <exclude>node/**</exclude>
+                        <exclude>node_modules/**</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                    <excludePackageNames>org.apache.hadoop.yarn.appcatalog</excludePackageNames>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+<!--
+    <profiles>
+      <profile>
+        <id>rest-docs</id>
+        <activation>
+          <file>
+            <exists>${basedir}/node_modules/.bin/apidoc</exists>
+          </file>
+        </activation>
+        <build>
+          <plugins>
+            <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>exec-maven-plugin</artifactId>
+              <executions>
+                <execution>
+                  <id>apidocs</id>
+                  <phase>package</phase>
+                  <goals>
+                    <goal>exec</goal>
+                  </goals>
+                  <configuration>
+                    <outputFile>${project.build.directory}/apidocs.log</outputFile>
+                    <executable>${basedir}/node/node</executable>
+                    <commandlineArgs>${basedir}/node_modules/.bin/apidoc -i src/main/java -o ${project.build.directory}/site/apidocs</commandlineArgs>
+                    <silent>true</silent>
+                  </configuration>
+                </execution>
+              </executions>
+            </plugin>
+          </plugins>
+        </build>
+      </profile>
+    </profiles>
+-->
+
+</project>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/application/AppCatalog.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/application/AppCatalog.java
new file mode 100644
index 0000000..07e3a6f
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/application/AppCatalog.java
@@ -0,0 +1,60 @@
+/*
+ * 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.appcatalog.application;
+
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+
+import org.apache.hadoop.yarn.appcatalog.controller.AppDetailsController;
+
+import java.util.Set;
+
+/**
+ * Jackson resource configuration class for Application Catalog.
+ */
+@ApplicationPath("service")
+public class AppCatalog extends Application {
+
+  @Override
+  public Set<Class<?>> getClasses() {
+    final Set<Class<?>> resources = new java.util.HashSet<>();
+    // following code can be used to customize Jersey 2.0 JSON provider:
+    try {
+      final Class<?> jsonProvider =
+          Class.forName("org.glassfish.jersey.jackson.JacksonFeature");
+      // Class jsonProvider =
+      // Class.forName("org.glassfish.jersey.moxy.json.MoxyJsonFeature");
+      // Class jsonProvider =
+      // Class.forName("org.glassfish.jersey.jettison.JettisonFeature");
+      resources.add(jsonProvider);
+    } catch (final ClassNotFoundException ex) {
+      ex.printStackTrace();
+    }
+    addRestResourceClasses(resources);
+    return resources;
+  }
+
+  /**
+   * Add your own resources here.
+   */
+  private void addRestResourceClasses(final Set<Class<?>> resources) {
+    resources.add(AppDetailsController.class);
+  }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/application/AppCatalogSolrClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/application/AppCatalogSolrClient.java
new file mode 100644
index 0000000..1397722
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/application/AppCatalogSolrClient.java
@@ -0,0 +1,359 @@
+/*
+ * 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.appcatalog.application;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Random;
+
+import org.apache.hadoop.yarn.appcatalog.model.AppEntry;
+import org.apache.hadoop.yarn.appcatalog.model.AppStoreEntry;
+import org.apache.hadoop.yarn.appcatalog.model.Application;
+import org.apache.hadoop.yarn.appcatalog.utils.RandomWord;
+import org.apache.hadoop.yarn.appcatalog.utils.WordLengthException;
+import org.apache.hadoop.yarn.service.api.records.Service;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.client.solrj.response.UpdateResponse;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrInputDocument;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Driver class for accessing Solr.
+ */
+public class AppCatalogSolrClient {
+
+  private static final Log LOG = LogFactory.getLog(AppCatalogSolrClient.class);
+  private static String urlString;
+
+  public AppCatalogSolrClient() {
+    // Locate Solr URL
+    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+    InputStream input =
+        classLoader.getResourceAsStream("appcatalog.properties");
+    Properties properties = new Properties();
+    try {
+      properties.load(input);
+      urlString = properties.getProperty("solr_url");
+    } catch (IOException e) {
+      LOG.error("Error reading appcatalog configuration: ", e);
+    }
+  }
+
+  public SolrClient getSolrClient() {
+    return new HttpSolrClient.Builder(urlString).build();
+  }
+
+  public List<AppStoreEntry> getRecommendedApps() {
+    List<AppStoreEntry> apps = new ArrayList<AppStoreEntry>();
+    SolrClient solr = getSolrClient();
+    SolrQuery query = new SolrQuery();
+    query.setQuery("*:*");
+    query.setFilterQueries("type_s:AppStoreEntry");
+    query.setRows(40);
+    QueryResponse response;
+    try {
+      response = solr.query(query);
+      Iterator<SolrDocument> list = response.getResults().listIterator();
+      while (list.hasNext()) {
+        SolrDocument d = list.next();
+        AppStoreEntry entry = new AppStoreEntry();
+        entry.setId(d.get("id").toString());
+        entry.setOrg(d.get("org_s").toString());
+        entry.setName(d.get("name_s").toString());
+        entry.setDesc(d.get("desc_s").toString());
+        if (d.get("icon_s")!=null) {
+          entry.setIcon(d.get("icon_s").toString());
+        }
+        entry.setLike(Integer.valueOf(d.get("like_i").toString()));
+        entry.setDownload(Integer.valueOf(d.get("download_i").toString()));
+        apps.add(entry);
+      }
+    } catch (SolrServerException | IOException e) {
+      LOG.error("Error getting a list of recommended applications: ", e);
+    }
+    return apps;
+  }
+
+  public List<AppStoreEntry> search(String keyword) {
+    List<AppStoreEntry> apps = new ArrayList<AppStoreEntry>();
+    SolrClient solr = getSolrClient();
+    SolrQuery query = new SolrQuery();
+    if (keyword.length()==0) {
+      query.setQuery("*:*");
+      query.setFilterQueries("type_s:AppStoreEntry");
+    } else {
+      query.setQuery(keyword);
+      query.setFilterQueries("type_s:AppStoreEntry");
+    }
+    query.setRows(40);
+    QueryResponse response;
+    try {
+      response = solr.query(query);
+      Iterator<SolrDocument> list = response.getResults().listIterator();
+      while (list.hasNext()) {
+        SolrDocument d = list.next();
+        AppStoreEntry entry = new AppStoreEntry();
+        entry.setId(d.get("id").toString());
+        entry.setOrg(d.get("org_s").toString());
+        entry.setName(d.get("name_s").toString());
+        entry.setDesc(d.get("desc_s").toString());
+        entry.setLike(Integer.valueOf(d.get("like_i").toString()));
+        entry.setDownload(Integer.valueOf(d.get("download_i").toString()));
+        apps.add(entry);
+      }
+    } catch (SolrServerException | IOException e) {
+      LOG.error("Error in searching for applications: ", e);
+    }
+    return apps;
+  }
+
+  public List<AppEntry> listAppEntries() {
+    List<AppEntry> list = new ArrayList<AppEntry>();
+    ObjectMapper mapper = new ObjectMapper();
+    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+    SolrClient solr = getSolrClient();
+    SolrQuery query = new SolrQuery();
+    query.setQuery("*:*");
+    query.setFilterQueries("type_s:AppEntry");
+    query.setRows(40);
+    QueryResponse response;
+    try {
+      response = solr.query(query);
+      Iterator<SolrDocument> appList = response.getResults().listIterator();
+      while (appList.hasNext()) {
+        SolrDocument d = appList.next();
+        AppEntry entry = new AppEntry();
+        entry.setId(d.get("id").toString());
+        entry.setName(d.get("name_s").toString());
+        entry.setApp(d.get("app_s").toString());
+        entry.setYarnfile(mapper.readValue(d.get("yarnfile_s").toString(),
+            Service.class));
+        list.add(entry);
+      }
+    } catch (SolrServerException | IOException e) {
+      LOG.error("Error in listing deployed applications: ", e);
+    }
+    return list;
+  }
+
+  public AppStoreEntry findAppStoreEntry(String id) {
+    AppStoreEntry entry = new AppStoreEntry();
+    ObjectMapper mapper = new ObjectMapper();
+    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+    SolrClient solr = getSolrClient();
+    SolrQuery query = new SolrQuery();
+    query.setQuery("id:" + id);
+    query.setFilterQueries("type_s:AppStoreEntry");
+    query.setRows(1);
+
+    QueryResponse response;
+    try {
+      response = solr.query(query);
+      Iterator<SolrDocument> appList = response.getResults().listIterator();
+      while (appList.hasNext()) {
+        SolrDocument d = appList.next();
+        entry.setId(d.get("id").toString());
+        entry.setOrg(d.get("org_s").toString());
+        entry.setName(d.get("name_s").toString());
+        entry.setDesc(d.get("desc_s").toString());
+        entry.setLike(Integer.valueOf(d.get("like_i").toString()));
+        entry.setDownload(Integer.valueOf(d.get("download_i").toString()));
+        Service yarnApp = mapper.readValue(d.get("yarnfile_s").toString(),
+            Service.class);
+        String name;
+        try {
+          Random r = new Random();
+          int low = 3;
+          int high = 10;
+          int seed = r.nextInt(high-low) + low;
+          int seed2 = r.nextInt(high-low) + low;
+          name = RandomWord.getNewWord(seed).toLowerCase() + "-" + RandomWord
+              .getNewWord(seed2).toLowerCase();
+        } catch (WordLengthException e) {
+          name = "c" + java.util.UUID.randomUUID().toString().substring(0, 11);
+        }
+        yarnApp.setName(name);
+        entry.setApp(yarnApp);
+      }
+    } catch (SolrServerException | IOException e) {
+      LOG.error("Error in finding deployed application: " + id, e);
+    }
+    return entry;
+  }
+
+  public AppEntry findAppEntry(String id) {
+    AppEntry entry = new AppEntry();
+    ObjectMapper mapper = new ObjectMapper();
+    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+    SolrClient solr = getSolrClient();
+    SolrQuery query = new SolrQuery();
+    query.setQuery("id:" + id);
+    query.setFilterQueries("type_s:AppEntry");
+    query.setRows(1);
+
+    QueryResponse response;
+    try {
+      response = solr.query(query);
+      Iterator<SolrDocument> appList = response.getResults().listIterator();
+      while (appList.hasNext()) {
+        SolrDocument d = appList.next();
+        entry.setId(d.get("id").toString());
+        entry.setApp(d.get("app_s").toString());
+        entry.setName(d.get("name_s").toString());
+        entry.setYarnfile(mapper.readValue(d.get("yarnfile_s").toString(),
+            Service.class));
+      }
+    } catch (SolrServerException | IOException e) {
+      LOG.error("Error in finding deployed application: " + id, e);
+    }
+    return entry;
+  }
+
+  public void deployApp(String id, Service service) throws SolrServerException,
+      IOException {
+    long download = 0;
+    ObjectMapper mapper = new ObjectMapper();
+    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    Collection<SolrInputDocument> docs = new HashSet<SolrInputDocument>();
+    SolrClient solr = getSolrClient();
+    // Find application information from AppStore
+    SolrQuery query = new SolrQuery();
+    query.setQuery("id:" + id);
+    query.setFilterQueries("type_s:AppStoreEntry");
+    query.setRows(1);
+    QueryResponse response = solr.query(query);
+    Iterator<SolrDocument> appList = response.getResults().listIterator();
+    AppStoreEntry entry = new AppStoreEntry();
+    while (appList.hasNext()) {
+      SolrDocument d = appList.next();
+      entry.setOrg(d.get("org_s").toString());
+      entry.setName(d.get("name_s").toString());
+      entry.setDesc(d.get("desc_s").toString());
+      entry.setLike(Integer.valueOf(d.get("like_i").toString()));
+      entry.setDownload(Integer.valueOf(d.get("download_i").toString()));
+      download = entry.getDownload() + 1;
+
+      // Update download count
+      docs.add(incrementDownload(d, download));
+    }
+
+    // increment download count for application
+
+    if (service!=null) {
+      // Register deployed application instance with AppList
+      SolrInputDocument request = new SolrInputDocument();
+      String name = service.getName();
+      request.addField("type_s", "AppEntry");
+      request.addField("id", name);
+      request.addField("name_s", name);
+      request.addField("app_s", entry.getOrg()+"/"+entry.getName());
+      request.addField("yarnfile_s", mapper.writeValueAsString(service));
+      docs.add(request);
+    }
+
+    // Commit Solr changes.
+    UpdateResponse detailsResponse = solr.add(docs);
+    if (detailsResponse.getStatus() != 0) {
+      throw new IOException("Unable to register docker instance "
+          + "with application entry.");
+    }
+    solr.commit();
+  }
+
+  private SolrInputDocument incrementDownload(SolrDocument doc,
+      long download) {
+    Collection<String> names = doc.getFieldNames();
+    SolrInputDocument s = new SolrInputDocument();
+    for (String name : names) {
+      if(!name.equals("_version_")) {
+        s.addField(name, doc.getFieldValues(name));
+      }
+    }
+    s.setField("download_i", download++);
+    return s;
+  }
+
+  public void deleteApp(String id) {
+    SolrClient solr = getSolrClient();
+    try {
+      solr.deleteById(id);
+      solr.commit();
+    } catch (SolrServerException | IOException e) {
+      LOG.error("Error in removing deployed application: "+id, e);
+    }
+  }
+
+  public void register(Application app) throws IOException {
+    Collection<SolrInputDocument> docs = new HashSet<SolrInputDocument>();
+    SolrClient solr = getSolrClient();
+    ObjectMapper mapper = new ObjectMapper();
+    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    try {
+      SolrInputDocument buffer = new SolrInputDocument();
+      buffer.setField("id", java.util.UUID.randomUUID().toString()
+          .substring(0, 11));
+      buffer.setField("org_s", app.getOrganization());
+      buffer.setField("name_s", app.getName());
+      buffer.setField("desc_s", app.getDescription());
+      if (app.getIcon() != null) {
+        buffer.setField("icon_s", app.getIcon());
+      }
+      buffer.setField("type_s", "AppStoreEntry");
+      buffer.setField("like_i", 0);
+      buffer.setField("download_i", 0);
+
+      // Keep only YARN data model for yarnfile field
+      String yarnFile = mapper.writeValueAsString(app);
+      LOG.info("app:"+yarnFile);
+      Service yarnApp = mapper.readValue(yarnFile, Service.class);
+      buffer.setField("yarnfile_s", mapper.writeValueAsString(yarnApp));
+
+      docs.add(buffer);
+      // Commit Solr changes.
+      UpdateResponse detailsResponse = solr.add(docs);
+      if (detailsResponse.getStatus() != 0) {
+        throw new IOException("Unable to register application " +
+            "in Application Store.");
+      }
+      solr.commit();
+    } catch (SolrServerException | IOException e) {
+      throw new IOException("Unable to register application " +
+          "in Application Store. "+ e.getMessage());
+    }
+  }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/application/YarnServiceClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/application/YarnServiceClient.java
new file mode 100644
index 0000000..667d218
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/application/YarnServiceClient.java
@@ -0,0 +1,174 @@
+/*
+ * 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.appcatalog.application;
+
+import java.io.IOException;
+
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.yarn.appcatalog.model.AppEntry;
+import org.apache.hadoop.yarn.service.api.records.Service;
+import org.apache.hadoop.yarn.service.api.records.KerberosPrincipal;
+import org.apache.hadoop.yarn.service.client.ApiServiceClient;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.api.client.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+
+/**
+ * Driver class for calling YARN Resource Manager REST API.
+ */
+public class YarnServiceClient {
+
+  private static final Log LOG = LogFactory.getLog(YarnServiceClient.class);
+  private static Configuration conf = new Configuration();
+  private static ClientConfig getClientConfig() {
+    ClientConfig config = new DefaultClientConfig();
+    config.getProperties().put(ClientConfig.PROPERTY_CHUNKED_ENCODING_SIZE, 0);
+    config.getProperties()
+        .put(ClientConfig.PROPERTY_BUFFER_RESPONSE_ENTITY_ON_EXCEPTION, true);
+    return config;
+  }
+
+  private ApiServiceClient asc;
+
+  public YarnServiceClient() {
+    try {
+      asc = new ApiServiceClient(conf);
+    } catch (Exception e) {
+      LOG.error("Error initialize YARN Service Client: {}", e);
+    }
+  }
+
+  public void createApp(Service app) {
+    ObjectMapper mapper = new ObjectMapper();
+    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    ClientResponse response;
+    try {
+      boolean useKerberos = UserGroupInformation.isSecurityEnabled();
+      if (useKerberos) {
+        KerberosPrincipal kerberos = new KerberosPrincipal();
+        String[] temp = System.getenv("PRINCIPAL").split("@");
+        String[] temp2 = temp[0].split("/");
+        StringBuilder sb = new StringBuilder();
+        sb.append(temp2[0]);
+        sb.append("/");
+        sb.append("_HOST");
+        sb.append("@");
+        sb.append(temp[1]);
+        String keytab = System.getenv("KEYTAB");
+        if (!keytab.startsWith("file://")) {
+          keytab = "file://" + keytab;
+        }
+        kerberos.setPrincipalName(sb.toString());
+        kerberos.setKeytab(keytab);
+        app.setKerberosPrincipal(kerberos);
+      }
+      response = asc.getApiClient().post(ClientResponse.class,
+          mapper.writeValueAsString(app));
+      if (response.getStatus() >= 299) {
+        String message = response.getEntity(String.class);
+        throw new RuntimeException("Failed : HTTP error code : "
+            + response.getStatus() + " error: " + message);
+      }
+    } catch (UniformInterfaceException | ClientHandlerException
+        | IOException e) {
+      LOG.error("Error in deploying application: ", e);
+    }
+  }
+
+  public void deleteApp(String appInstanceId) {
+    ClientResponse response;
+    try {
+      response = asc.getApiClient(asc.getServicePath(appInstanceId))
+          .delete(ClientResponse.class);
+      if (response.getStatus() >= 299) {
+        String message = response.getEntity(String.class);
+        throw new RuntimeException("Failed : HTTP error code : "
+            + response.getStatus() + " error: " + message);
+      }
+    } catch (UniformInterfaceException | ClientHandlerException
+        | IOException e) {
+      LOG.error("Error in deleting application: ", e);
+    }
+  }
+
+  public void restartApp(Service app) throws JsonProcessingException {
+    ObjectMapper mapper = new ObjectMapper();
+    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    String appInstanceId = app.getName();
+    String yarnFile = mapper.writeValueAsString(app);
+    ClientResponse response;
+    try {
+      response = asc.getApiClient(asc.getServicePath(appInstanceId))
+          .put(ClientResponse.class, yarnFile);
+      if (response.getStatus() >= 299) {
+        String message = response.getEntity(String.class);
+        throw new RuntimeException("Failed : HTTP error code : "
+            + response.getStatus() + " error: " + message);
+      }
+    } catch (UniformInterfaceException | ClientHandlerException
+        | IOException e) {
+      LOG.error("Error in restarting application: ", e);
+    }
+  }
+
+  public void stopApp(Service app) throws JsonProcessingException {
+    ObjectMapper mapper = new ObjectMapper();
+    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    String appInstanceId = app.getName();
+    String yarnFile = mapper.writeValueAsString(app);
+    ClientResponse response;
+    try {
+      response = asc.getApiClient(asc.getServicePath(appInstanceId))
+          .put(ClientResponse.class, yarnFile);
+      if (response.getStatus() >= 299) {
+        String message = response.getEntity(String.class);
+        throw new RuntimeException("Failed : HTTP error code : "
+            + response.getStatus() + " error: " + message);
+      }
+    } catch (UniformInterfaceException | ClientHandlerException
+        | IOException e) {
+      LOG.error("Error in stopping application: ", e);
+    }
+  }
+
+  public void getStatus(AppEntry entry) {
+    ObjectMapper mapper = new ObjectMapper();
+    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    String appInstanceId = entry.getName();
+    Service app = null;
+    try {
+      String yarnFile = asc.getApiClient(asc.getServicePath(appInstanceId))
+          .get(String.class);
+      app = mapper.readValue(yarnFile, Service.class);
+      entry.setYarnfile(app);
+    } catch (UniformInterfaceException | IOException e) {
+      LOG.error("Error in fetching application status: ", e);
+    }
+  }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/application/package-info.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/application/package-info.java
new file mode 100644
index 0000000..e8077ca
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/application/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ *
+ */
+/**
+ * Application Catalog.
+ */
+package org.apache.hadoop.yarn.appcatalog.application;
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/controller/AppDetailsController.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/controller/AppDetailsController.java
new file mode 100644
index 0000000..db6973d
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/controller/AppDetailsController.java
@@ -0,0 +1,265 @@
+/*
+ * 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.appcatalog.controller;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.hadoop.yarn.appcatalog.application.AppCatalogSolrClient;
+import org.apache.hadoop.yarn.appcatalog.application.YarnServiceClient;
+import org.apache.hadoop.yarn.appcatalog.model.AppEntry;
+import org.apache.hadoop.yarn.service.api.records.Service;
+import org.apache.hadoop.yarn.service.api.records.ServiceState;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+/**
+ * Application catalog REST API for displaying application details.
+ */
+@Path("/app_details")
+public class AppDetailsController {
+
+  public AppDetailsController() {
+  }
+
+  /**
+   * List detail information about the deployed application.
+   *
+   * @apiGroup AppDetailController
+   * @apiName getDetails
+   * @api {get} /app_details/config/{id}  Check config of application instance.
+   * @apiParam {String} id Application ID to fetch configuration.
+   * @apiSuccess {Object} AppEntry Application configuration.
+   * @apiSuccessExample {json} Success-Response:
+   *     HTTP/1.1 200 OK
+   *     {
+   *       "id":"howita_man",
+   *        "name":"howita_man",
+   *        "app":"Jenkins-ci.org/Jenkins",
+   *        "yarnfile":{
+   *           "name":"howita_man",
+   *           "lifetime":3600,
+   *           "containers":[
+   *           ],
+   *           "components":[
+   *              {
+   *                 "name":"jenkins",
+   *                 "dependencies":[
+   *                 ],
+   *                 "artifact":{
+   *                    "id":"eyang-1.openstacklocal:5000/jenkins:latest",
+   *                    "type":"DOCKER"
+   *                 },
+   *                 "launch_command":"",
+   *                 "resource":{
+   *                    "uri":null,
+   *                    "profile":null,
+   *                    "cpus":1,
+   *                    "memory":"2048"
+   *                 },
+   *                 "number_of_containers":1,
+   *                 "run_privileged_container":false,
+   *                 "configuration":{
+   *                    "properties":{
+   *                    },
+   *                    "env":{
+   *                    },
+   *                    "files":[
+   *                    ]
+   *                 },
+   *                 "quicklinks":[
+   *                 ],
+   *                 "containers":[
+   *                 ]
+   *              }
+   *           ],
+   *           "configuration":{
+   *              "properties":{
+   *              },
+   *              "env":{
+   *              },
+   *              "files":[
+   *              ]
+   *           },
+   *           "quicklinks":{
+   *              "Jenkins UI":"http://jenkins.howita_man.yarn.${DOMAIN}:8080/"
+   *           }
+   *        }
+   *     }
+   * @param id - Application ID
+   * @return application entry-
+   */
+  @Path("config/{id}")
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  public AppEntry getDetails(@PathParam("id") String id) {
+    AppCatalogSolrClient sc = new AppCatalogSolrClient();
+    return sc.findAppEntry(id);
+  }
+
+  /**
+   * Check application status.
+   *
+   * @apiGroup AppDetailController
+   * @apiName getStatus
+   * @api {get} /app_details/status/{id}  Check status of application instance.
+   * @apiParam {String} id Application ID to check.
+   * @apiSuccessExample {json} Success-Response:
+   *     HTTP/1.1 200 OK
+   *     {
+   *       "id":"howita_man",
+   *        "name":"howita_man",
+   *        "app":"Jenkins-ci.org/Jenkins",
+   *        "yarnfile":{
+   *           "name":"howita_man",
+   *           "lifetime":3099,
+   *           "containers":[
+   *           ],
+   *           "id":"application_1503694240849_0043",
+   *           "components":[
+   *              {
+   *                 "name":"jenkins",
+   *                 "dependencies":[
+   *                 ],
+   *                 "artifact":{
+   *                    "id":"eyang-1.openstacklocal:5000/jenkins:latest",
+   *                    "type":"DOCKER"
+   *                 },
+   *                 "launch_command":"",
+   *                 "resource":{
+   *                    "uri":null,
+   *                    "profile":null,
+   *                    "cpus":1,
+   *                    "memory":"2048"
+   *                 },
+   *                 "number_of_containers":1,
+   *                 "run_privileged_container":false,
+   *                 "configuration":{
+   *                    "properties":{
+   *                    },
+   *                    "env":{
+   *                    },
+   *                    "files":[
+   *                    ]
+   *                 },
+   *                 "quicklinks":[
+   *                 ],
+   *                 "containers":[
+   *                    {
+   *                       "id":"container_1503694240849_0043_01_000002",
+   *                       "launch_time":1504630535403,
+   *                       "bare_host":"eyang-4.openstacklocal",
+   *                       "state":"READY",
+   *                       "component_name":"jenkins-0"
+   *                    }
+   *                 ]
+   *              }
+   *           ],
+   *           "configuration":{
+   *              "properties":{
+   *              },
+   *              "env":{
+   *              },
+   *              "files":[
+   *              ]
+   *           },
+   *           "quicklinks":{
+   *              "Jenkins UI":"http://jenkins.howita_man.yarn.${DOMAIN}:8080/"
+   *           }
+   *        }
+   *     }
+   * @apiSuccess {Object} text Give status
+   * @param id - Application ID
+   * @return application entry
+   */
+  @Path("status/{id}")
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  public AppEntry getStatus(@PathParam("id") String id) {
+    AppCatalogSolrClient sc = new AppCatalogSolrClient();
+    AppEntry appEntry = sc.findAppEntry(id);
+    YarnServiceClient yc = new YarnServiceClient();
+    yc.getStatus(appEntry);
+    return appEntry;
+  }
+
+  /**
+   * Stop an application.
+   *
+   * @apiGroup AppDetailController
+   * @apiName stopApp
+   * @api {post} /app_details/stop/{id}  Stop one instance of application.
+   * @apiParam {String} id Application ID to stop.
+   * @apiSuccess {String} text Give deployment status
+   * @apiError BadRequest Requested application does not stop.
+   * @param id - Application ID
+   * @return Web response code
+   */
+  @Path("stop/{id}")
+  @POST
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response stopApp(@PathParam("id") String id) {
+    AppCatalogSolrClient sc = new AppCatalogSolrClient();
+    AppEntry app = sc.findAppEntry(id);
+    Service yarnApp = app.getYarnfile();
+    yarnApp.setState(ServiceState.STOPPED);
+    try {
+      YarnServiceClient yc = new YarnServiceClient();
+      yc.stopApp(yarnApp);
+    } catch (JsonProcessingException e) {
+      return Response.status(Status.BAD_REQUEST).build();
+    }
+    return Response.ok().build();
+  }
+
+  /**
+   * Restart an application.
+   *
+   * @apiGroup AppDetailController
+   * @apiName restartApp
+   * @api {post} /app_details/restart/{id}  Restart one instance of application.
+   * @apiParam {String} id Application ID to restart.
+   * @apiSuccess {String} text Give deployment status
+   * @apiError BadRequest Requested application does not restart.
+   * @param id - Application ID
+   * @return Web response code
+   */
+  @Path("restart/{id}")
+  @POST
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response restartApp(@PathParam("id") String id) {
+    AppCatalogSolrClient sc = new AppCatalogSolrClient();
+    AppEntry app = sc.findAppEntry(id);
+    Service yarnApp = app.getYarnfile();
+    yarnApp.setState(ServiceState.STARTED);
+    try {
+      YarnServiceClient yc = new YarnServiceClient();
+      yc.restartApp(yarnApp);
+    } catch (JsonProcessingException e) {
+      return Response.status(Status.BAD_REQUEST).build();
+    }
+    return Response.ok().build();
+  }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/controller/AppListController.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/controller/AppListController.java
new file mode 100644
index 0000000..d818f23
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/controller/AppListController.java
@@ -0,0 +1,182 @@
+/*
+ * 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.appcatalog.controller;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.hadoop.yarn.appcatalog.application.AppCatalogSolrClient;
+import org.apache.hadoop.yarn.appcatalog.application.YarnServiceClient;
+import org.apache.hadoop.yarn.appcatalog.model.AppEntry;
+import org.apache.hadoop.yarn.service.api.records.Service;
+import org.apache.solr.client.solrj.SolrServerException;
+
+/**
+ * Application deployment module.
+ */
+@Path("/app_list")
+@Produces({ MediaType.APPLICATION_JSON })
+public class AppListController {
+
+  public AppListController() {
+  }
+
+  /**
+   * Get Application List.
+   *
+   * @apiGroup AppListController
+   * @apiName get
+   * @api {get} /app_list  Get list of deployed applications.
+   * @apiSuccess {Object[]}  List<AppEntry> List of deployed Applications.
+   * @apiSuccessExample {json} Success-Response:
+   *     HTTP/1.1 200 OK
+   *     [
+   *        {
+   *           "id":"howita-man",
+   *           "name":"howita-man",
+   *           "app":"Jenkins-ci.org/Jenkins",
+   *           "yarnfile":{
+   *              "name":"howita_man",
+   *              "lifetime":3600,
+   *              "containers":[
+   *              ],
+   *              "components":[
+   *                 {
+   *                    "name":"jenkins",
+   *                    "dependencies":[
+   *                    ],
+   *                    "artifact":{
+   *                       "id":"eyang-1.openstacklocal:5000/jenkins:latest",
+   *                       "type":"DOCKER"
+   *                    },
+   *                    "launch_command":"",
+   *                    "resource":{
+   *                       "uri":null,
+   *                       "profile":null,
+   *                       "cpus":1,
+   *                       "memory":"2048"
+   *                    },
+   *                    "number_of_containers":1,
+   *                    "run_privileged_container":false,
+   *                    "configuration":{
+   *                       "properties":{
+   *                       },
+   *                       "env":{
+   *                       },
+   *                       "files":[
+   *                       ]
+   *                    },
+   *                    "quicklinks":[
+   *                    ],
+   *                    "containers":[
+   *                    ]
+   *                 }
+   *              ],
+   *              "configuration":{
+   *                 "properties":{
+   *                 },
+   *                 "env":{
+   *                 },
+   *                 "files":[
+   *                 ]
+   *              },
+   *              "quicklinks":{
+   *                 "Jenkins UI":"http://jenkins.${SERVICE_NAME}.${USER}.${DOMAIN}:8080/"
+   *              }
+   *           }
+   *        },
+   *        {
+   *        ...
+   *        }
+   *     ]
+   * @return - Active application deployed by current user.
+   */
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  public List<AppEntry> getList() {
+    AppCatalogSolrClient sc = new AppCatalogSolrClient();
+    return sc.listAppEntries();
+  }
+
+  /**
+   * Delete an application.
+   *
+   * @apiGroup AppListController
+   * @apiName delete
+   * @api {delete} /app_list  Delete one instance of application.
+   * @apiParam {String} id Application name to delete.
+   * @apiSuccess {String} text Delete request accepted
+   * @param id - application ID
+   * @param name - application name
+   * @return Web response
+   */
+  @DELETE
+  @Path("{id}/{name}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response delete(@PathParam("id") String id,
+      @PathParam("name") String name) {
+    AppCatalogSolrClient sc = new AppCatalogSolrClient();
+    sc.deleteApp(id);
+    YarnServiceClient yc = new YarnServiceClient();
+    yc.deleteApp(name);
+    return Response.status(Status.ACCEPTED).build();
+  }
+
+  /**
+   * Deploy an application.
+   *
+   * @apiGroup AppListController
+   * @apiName deploy
+   * @api {post} /app_list/{id}  Deploy one instance of application.
+   * @apiParam {String} id Application ID to deploy.
+   * @apiSuccess {String} text Give deployment status
+   * @apiError BadRequest Unable to deploy requested application.
+   * @param id - application ID
+   * @return Web response
+   */
+  @POST
+  @Path("{id}")
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response deploy(@PathParam("id") String id, Service service) {
+    AppCatalogSolrClient sc = new AppCatalogSolrClient();
+    try {
+      sc.deployApp(id, service);
+    } catch (SolrServerException | IOException e) {
+      return Response.status(Status.BAD_REQUEST).entity(e.toString()).build();
+    }
+    YarnServiceClient yc = new YarnServiceClient();
+    yc.createApp(service);
+    String output = "{\"status\":\"Application deployed.\",\"id\":\"" +
+        service.getName() + "\"}";
+    return Response.status(Status.ACCEPTED).entity(output).build();
+  }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/controller/AppStoreController.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/controller/AppStoreController.java
new file mode 100644
index 0000000..5abb548
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/controller/AppStoreController.java
@@ -0,0 +1,198 @@
+/*
+ * 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.appcatalog.controller;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.hadoop.yarn.appcatalog.application.AppCatalogSolrClient;
+import org.apache.hadoop.yarn.appcatalog.model.AppStoreEntry;
+import org.apache.hadoop.yarn.appcatalog.model.Application;
+
+/**
+ * Application catalog REST API for searching and recommending
+ * applications.
+ *
+ */
+@Path("/app_store")
+public class AppStoreController {
+
+  public AppStoreController() {
+  }
+
+  /**
+   * Display the most frequently used applications on YARN AppCatalog home page.
+   *
+   * @apiGroup AppStoreController
+   * @apiName get
+   * @api {get} /app_store/recommended  Display recommended applications.
+   * @apiSuccess {Object} AppEntry Application configuration.
+   * @apiSuccessExample {json} Success-Response:
+   *     HTTP/1.1 200 OK
+   *     [
+   *        {
+   *           "id":"96b7833a-e3",
+   *           "org":"Hortonworks",
+   *           "name":"LAMP",
+   *           "desc":"Linux Apache MySQL PHP web application",
+   *           "icon":"/css/img/feather.png",
+   *           "like":0,
+   *           "download":0,
+   *           "app":null
+   *        },
+   *        {
+   *        ...
+   *        }
+   *     ]
+   * @return - List of YARN applications
+   */
+  @GET
+  @Path("recommended")
+  @Produces(MediaType.APPLICATION_JSON)
+  public List<AppStoreEntry> get() {
+    AppCatalogSolrClient sc = new AppCatalogSolrClient();
+    return sc.getRecommendedApps();
+  }
+
+  /**
+   * Search for yarn applications from solr.
+   *
+   * @apiGroup AppStoreController
+   * @apiName search
+   * @api {get} /app_store/search  Find application from appstore.
+   * @apiParam {String} q Keyword to search.
+   * @apiSuccess {Object} AppStoreEntry List of matched applications.
+   * @apiSuccessExample {json} Success-Response:
+   *     HTTP/1.1 200 OK
+   *     [
+   *        {
+   *           "id":"96b7833a-e3",
+   *           "org":"Hortonworks",
+   *           "name":"LAMP",
+   *           "desc":"Linux Apache MySQL PHP web application",
+   *           "icon":"/css/img/feather.png",
+   *           "like":0,
+   *           "download":0,
+   *           "app":null
+   *        },
+   *        {
+   *        ...
+   *        }
+   *     ]
+   * @param keyword - search for keyword
+   * @return - List of YARN applications matching keyword search.
+   */
+  @GET
+  @Path("search")
+  @Produces(MediaType.APPLICATION_JSON)
+  public List<AppStoreEntry> search(@QueryParam("q") String keyword) {
+    AppCatalogSolrClient sc = new AppCatalogSolrClient();
+    return sc.search(keyword);
+  }
+
+  /**
+   * Find yarn application from solr.
+   *
+   * @param id Application ID
+   * @return AppEntry
+   */
+  @GET
+  @Path("get/{id}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public AppStoreEntry get(@PathParam("id") String id) {
+    AppCatalogSolrClient sc = new AppCatalogSolrClient();
+    return sc.findAppStoreEntry(id);
+  }
+
+  /**
+   * Register an application.
+   *
+   * @apiGroup AppStoreController
+   * @apiName register
+   * @api {post} /app_store/register  Register an application in appstore.
+   * @apiParam {Object} app Application definition.
+   * @apiParamExample {json} Request-Example:
+   *     {
+   *       "name": "Jenkins",
+   *       "organization": "Jenkins-ci.org",
+   *       "description": "The leading open source automation server",
+   *       "icon": "/css/img/jenkins.png",
+   *       "lifetime": "3600",
+   *       "components": [
+   *         {
+   *           "name": "jenkins",
+   *           "number_of_containers": 1,
+   *           "artifact": {
+   *             "id": "eyang-1.openstacklocal:5000/jenkins:latest",
+   *             "type": "DOCKER"
+   *           },
+   *           "launch_command": "",
+   *           "resource": {
+   *             "cpus": 1,
+   *             "memory": "2048"
+   *           },
+   *           "configuration": {
+   *             "env": {
+   *             },
+   *             "files": [
+   *             ]
+   *           }
+   *         }
+   *       ],
+   *       "quicklinks": {
+   *         "Jenkins UI": "http://jenkins.${SERVICE_NAME}.${USER}.${DOMAIN}:8080/"
+   *       }
+   *     }
+   * @apiSuccess {String} Response Application register result.
+   * @apiError BadRequest Error in process application registration.
+   * @param app - Yarnfile in JSON form
+   * @return Web response
+   */
+  @POST
+  @Path("register")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response register(Application app) {
+    try {
+      if (app.getName()==null) {
+        throw new IOException("Application name can not be empty.");
+      }
+      if (app.getOrganization()==null) {
+        throw new IOException("Application organization can not be empty.");
+      }
+      if (app.getDescription()==null) {
+        throw new IOException("Application description can not be empty.");
+      }
+      AppCatalogSolrClient sc = new AppCatalogSolrClient();
+      sc.register(app);
+    } catch (IOException e) {
+      return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+    }
+    return Response.status(Status.ACCEPTED).build();
+  }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/controller/package-info.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/controller/package-info.java
new file mode 100644
index 0000000..f2507b1
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/controller/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ *
+ */
+/**
+ * Application Catalog controllers.
+ */
+package org.apache.hadoop.yarn.appcatalog.controller;
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/AppDetails.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/AppDetails.java
new file mode 100644
index 0000000..42012cf
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/AppDetails.java
@@ -0,0 +1,76 @@
+/*
+ * 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.appcatalog.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * Data model for user defined application configuration.
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
+public class AppDetails {
+  private String image;
+  private String version;
+  private String[] ports;
+  private String[] volumes;
+  private String[] env;
+
+  public String getImage() {
+    return image;
+  }
+
+  public void setImage(String image) {
+    this.image = image;
+  }
+
+  public String getVersion() {
+    return version;
+  }
+
+  public void setVersion(String version) {
+    this.version = version;
+  }
+
+  public String[] getPorts() {
+    return ports;
+  }
+
+  public void setPorts(String[] ports2) {
+    this.ports = ports2;
+  }
+
+  public String[] getVolumes() {
+    return volumes;
+  }
+
+  public void setVolumes(String[] volumes) {
+    this.volumes = volumes;
+  }
+
+  public String[] getEnv() {
+    return env;
+  }
+
+  public void setEnv(String[] env) {
+    this.env = env;
+  }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/AppEntry.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/AppEntry.java
new file mode 100644
index 0000000..acba4d9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/AppEntry.java
@@ -0,0 +1,72 @@
+/*
+ * 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.appcatalog.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.hadoop.yarn.service.api.records.Service;
+
+/**
+ * Data model for deployed application.
+ *
+ */
+@XmlType(namespace="http://hadoop.apache.org", name="AppEntry")
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
+public class AppEntry {
+  private String id;
+  private String name;
+  private String app;
+  private Service yarnfile;
+
+  public String getId() {
+    return id;
+  }
+
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getApp() {
+    return app;
+  }
+
+  public void setApp(String app) {
+    this.app = app;
+  }
+
+  public Service getYarnfile() {
+    return yarnfile;
+  }
+
+  public void setYarnfile(Service yarnfile) {
+    this.yarnfile = yarnfile;
+  }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/AppStoreEntry.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/AppStoreEntry.java
new file mode 100644
index 0000000..f245297
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/AppStoreEntry.java
@@ -0,0 +1,106 @@
+/*
+ * 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.appcatalog.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.hadoop.yarn.service.api.records.Service;
+
+/**
+ * Data model of application template stored in application catalog.
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
+public class AppStoreEntry {
+  private String id;
+  private String org;
+  private String name;
+  private String desc;
+  private String icon = "/css/img/feather.png";
+  private long like;
+  private long download;
+  private Service app;
+
+  public String getOrg() {
+    return org;
+  }
+
+  public void setOrg(String org) {
+    this.org = org;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getDesc() {
+    return desc;
+  }
+
+  public void setDesc(String desc) {
+    this.desc = desc;
+  }
+
+  public long getLike() {
+    return like;
+  }
+
+  public void setLike(long like) {
+    this.like = like;
+  }
+
+  public long getDownload() {
+    return download;
+  }
+
+  public void setDownload(long download) {
+    this.download = download;
+  }
+
+  public String getId() {
+    return id;
+  }
+
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  public Service getApp() {
+    return app;
+  }
+
+  public void setApp(Service app) {
+    this.app = app;
+  }
+
+  public String getIcon() {
+    return icon;
+  }
+
+  public void setIcon(String icon) {
+    this.icon = icon;
+  }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/Application.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/Application.java
new file mode 100644
index 0000000..dbc31b1
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/Application.java
@@ -0,0 +1,67 @@
+/*
+ * 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.appcatalog.model;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.hadoop.yarn.service.api.records.Service;
+
+/**
+ * Data model of display recommended applications and descriptions.
+ */
+@XmlRootElement
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonPropertyOrder({ "organization", "name", "description", "icon" })
+public class Application extends Service {
+  private static final long serialVersionUID = -1776203219305414248L;
+
+  private String organization;
+  private String description;
+  private String icon;
+
+  @JsonProperty("organization")
+  public String getOrganization() {
+    return organization;
+  }
+  public void setOrganization(String organization) {
+    this.organization = organization;
+  }
+
+  @JsonProperty("description")
+  public String getDescription() {
+    return description;
+  }
+  public void setDescription(String description) {
+    this.description = description;
+  }
+
+  @JsonProperty("icon")
+  public String getIcon() {
+    return icon;
+  }
+  public void setIcon(String icon) {
+    this.icon = icon;
+  }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/package-info.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/package-info.java
new file mode 100644
index 0000000..9a20b99
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/model/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ *
+ */
+/**
+ * Application Catalog Data Models.
+ */
+package org.apache.hadoop.yarn.appcatalog.model;
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/utils/RandomWord.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/utils/RandomWord.java
new file mode 100644
index 0000000..4346d1e
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/utils/RandomWord.java
@@ -0,0 +1,422 @@
+/*
+ * 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.appcatalog.utils;
+
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * Random word generator utility.
+ */
+public final class RandomWord {
+
+  private RandomWord() {
+  }
+
+  public static String getNewWord(int wordLength) throws WordLengthException {
+    if (wordLength < 3 || wordLength > 15) {
+      throw new WordLengthException(
+          "Word length error, words must be between 3 and 15 characters long.");
+    }
+    String theNewWord = "e";
+    while (theNewWord.equals("e")) {
+      try {
+        theNewWord = generateRandomWord(wordLength);
+      } catch (Exception e) {
+      }
+    }
+    return theNewWord;
+  }
+
+  private static String generateRandomWord(int wordLength) {
+    String randomWord;
+    // -----------------------------------------------------------------------
+    // Bigram source and general concept based on
+    // https://github.com/scrollback/scrollback & described in
+    // https://www.hackerearth.com/notes/random-pronouncable-text-generator/
+    String[] startBiGram = {"TH", "OF", "AN", "IN", "TO", "CO", "BE", "HE",
+        "RE", "HA", "WA", "FO", "WH", "MA", "WI", "ON", "HI", "PR", "ST", "NO",
+        "IS", "IT", "SE", "WE", "AS", "CA", "DE", "SO", "MO", "SH", "DI", "AL",
+        "AR", "LI", "WO", "FR", "PA", "ME", "AT", "SU", "BU", "SA", "FI", "NE",
+        "CH", "PO", "HO", "DO", "OR", "UN", "LO", "EX", "BY", "FA", "LA", "LE",
+        "PE", "MI", "SI", "YO", "TR", "BA", "GO", "BO", "GR", "TE", "EN", "OU",
+        "RA", "AC", "FE", "PL", "CL", "SP", "BR", "EV", "TA", "DA", "AB", "TI",
+        "RO", "MU", "EA", "NA", "SC", "AD", "GE", "YE", "AF", "AG", "UP", "AP",
+        "DR", "US", "PU", "CE", "IF", "RI", "VI", "IM", "AM", "KN", "OP", "CR",
+        "OT", "JU", "QU", "TW", "GA", "VA", "VE", "PI", "GI", "BI", "FL", "BL",
+        "EL", "JO", "FU", "HU", "CU", "RU", "OV", "MY", "OB", "KE", "EF", "PH",
+        "CI", "KI", "NI", "SL", "EM", "SM", "VO", "MR", "WR", "ES", "DU", "TU",
+        "AU", "NU", "GU", "OW", "SY", "JA", "OC", "EC", "ED", "ID", "JE", "AI",
+        "EI", "SK", "OL", "GL", "EQ", "LU", "AV", "SW", "AW", "EY", "TY"};
+    String[] lookupBiGram = {"TH", "AN", "IN", "IO", "EN", "TI", "FO", "HE",
+        "HA", "HI", "TE", "AT", "ER", "AL", "WA", "VE", "CO", "RE", "IT", "WI",
+        "ME", "NC", "ON", "PR", "AR", "ES", "EV", "ST", "EA", "IV", "EC", "NO",
+        "OU", "PE", "IL", "IS", "MA", "AV", "OM", "IC", "GH", "DE", "AI", "CT",
+        "IG", "ID", " OR", "OV", "UL", "YO", "BU", "RA", "FR", "RO", "WH", "OT",
+        "BL", "NT", "UN", "TR", "HO", "AC", "TU", "WE", "CA", "SH", "UR", "IE",
+        "PA", "TO", "EE", "LI", "RI", "UG", "AM", "ND", "US", "LL", "AS", "TA",
+        "LE", "MO", "WO", "MI", "AB", "EL", "IA", "NA", "SS", "AG", "TT", "NE",
+        "PL", " LA", "OS", "CE", "DI", "BE", "AP", "SI", "NI", "OW", "SO", "AK",
+        "CH", "EM", "IM", "SE", "NS", "PO", "EI", "EX", "KI", "UC", "AD", "GR",
+        "IR", "NG", "OP", "SP", "OL", "DA", "NL", "TL", "LO", "BO", "RS", "FE",
+        "FI", "SU", "GE", "MP", "UA", "OO", "RT", "SA", "CR", "FF", "IK", "MB",
+        " KE", "FA", "CI", "EQ", "AF", "ET", "AY", "MU", "UE", "HR", "TW", "GI",
+        "OI", "VI", "CU", "FU", "ED", "QU", "UT", "RC", "OF", "CL", "FT", "IZ",
+        "PP", "RG", "DU", "RM", "YE", "RL", "DO", "AU", "EP", "BA", "JU", "RD",
+        "RU", "OG", "BR", "EF", "KN", "LS", "GA", "PI", "YI", "BI", "IB", "UB",
+        "VA", "OC", "IF", "RN", "RR", "SC", "TC", "CK", "DG", "DR", "MM", "NN",
+        "OD", "RV", "UD", "XP", "JE", "UM", "EG", "DL", "PH", "SL", "GO", "CC",
+        "LU", "OA", "PU", "UI", "YS", "ZA", "HU", "MR", "OE", "SY", "EO", "TY",
+        "UP", "FL", "LM", "NF", "RP", "OH", "NU", "XA", "OB", "VO", "DM", "GN",
+        " LD", "PT", "SK", "WR", "JO", "LT", "YT", "UF", "BJ", "DD", "EY", "GG",
+        "GL", "GU", "HT", "LV", "MS", "NM", "NV", "OK", "PM", "RK", "SW", "TM",
+        "XC", "ZE", "AW", "SM"};
+    String[][][] nextCharLookup = {
+        {{"E", "A", "I", "O", "R"}, {"E", "O"}},
+        {{"D", "T", "Y", "C", "S", "G", "N", "I", "O", "E", "A", "K"},
+            {"D", "T", "Y", "S", "G", "O", "E", "A", "K"}},
+        {{"G", "T", "E", "D", "S", "C", "A", "I", "K", "V", "U", "N", "F"},
+            {"G", "T", "E", "D", "S", "A", "K"}},
+        {{"N", "U", "R"}, {"N", "U", "R"}},
+        {{"T", "C", "D", "S", "E", "I", "G", "O", "N", "A"},
+            {"T", "D", "S", "E", "G", "O", "A"}},
+        {{"O", "N", "C", "V", "M", "L", "E", "T", "S", "A", "R", "F"},
+            {"N", "C", "M", "L", "E", "T", "S", "A", "R", "F"}},
+        {{"R", "U", "O", "L"}, {"R", "U", "O", "L"}},
+        {{"R", "N", "Y", "S", "M", "I", "A", "L", "D", "T"},
+            {"R", "N", "Y", "S", "M", "A", "L", "D", "T"}},
+        {{"T", "D", "V", "N", "S", "R", "P", "L"},
+            {"T", "D", "N", "S", "R", "L"}},
+        {{"S", "N", "C", "M", "L", "P", "G", "T", "R", "E"},
+            {"S", "N", "C", "M", "L", "P", "G", "T", "R", "E"}},
+        {{"R", "D", "N", "S", "M", "L", "E", "C", "A"},
+            {"R", "D", "N", "S", "M", "L", "E", "A"}},
+        {{"I", "E", "T", "H", "U", "O", "C"}, {"E", "H", "O"}},
+        {{"E", "S", "I", "A", "N", "Y", "T", "V", "M", "R", "O", "L", "G",
+             "F", "C"}, {"E", "S", "A", "N", "Y", "T", "M"}},
+        {{"L", "S", "I", "T", "E", "U", "O", "M", "K", "F", "A"},
+            {"L", "S", "T", "E", "F"}},
+        {{"S", "Y", "R", "T", "N", "L"}, {"S", "Y", "R", "T", "N", "L"}},
+        {{"R", "N", "L", "S", "D"}, {"R", "N", "L", "S", "D"}},
+        {{"N", "M", "U", "R", "L", "V", "S", "O"},
+            {"N", "M", "U", "R", "L", "O"}},
+        {{"S", "A", "D", "N", "E", "C", "L", "T", "P", "M", "V", "G", "F",
+             "Q"}, {"S", "A", "D", "N", "E", "L", "T", "P", "M"}},
+        {{"H", "I", "Y", "E", "S", "T", "A", "U"},
+            {"H", "Y", "E", "S", "A"}},
+        {{"T", "L", "N", "S"}, {"T", "L", "N", "S"}},
+        {{"N", "R", "D", "T", "S", "M", "A"},
+            {"N", "R", "D", "T", "S", "M", "A"}},
+        {{"E", "I", "H", "T", "R", "O", "L"}, {"E", "H", "T"}},
+        {{"S", "E", "T", "G", "A", "D", "L", "C", "V", "O", "I", "F"},
+            {"S", "E", "T", "G", "A", "D", "O"}},
+        {{"O", "E", "I", "A"}, {"E", "A"}},
+        {{"E", "T", "D", "Y", "S", "I", "R", "L", "M", "K", "G", "A", "O",
+             "N", "C"}, {"E", "T", "D", "Y", "S", "M", "K", "A", "N"}},
+        {{"S", "T", "E", "I", "P", "U", "C"}, {"S", "T", "E"}},
+        {{"E", "I"}, {"E"}},
+        {{"A", "R", "I", "E", "O", "U", "S"}, {"A", "E", "O", "S"}},
+        {{"R", "S", "T", "D", "L", "C", "N", "V", "M", "K"},
+            {"R", "S", "T", "D", "L", "N", "M"}},
+        {{"E", "I", "A"}, {"E"}},
+        {{"T", "O", "I", "E", "A", "U", "R", "H"}, {"T", "E", "H"}},
+        {{"T", "W", "R", "U", "N", "M"}, {"T", "W", "R", "U", "N", "M"}},
+        {{"T", "L", "R", "N", "S", "G", "P", "B"},
+            {"T", "L", "R", "N", "S", "P"}},
+        {{"R", "N", "C", "A", "D", "T", "O"}, {"R", "N", "A", "D", "T"}},
+        {{"L", "E", "I", "Y", "D", "A"}, {"L", "E", "Y", "D"}},
+        {{"T", "H", "S", "I", "E", "C", "M"}, {"T", "H", "S", "E", "M"}},
+        {{"N", "T", "L", "K", "D", "S", "I", "G"},
+            {"N", "T", "L", "D", "S"}},
+        {{"E", "I", "A"}, {"E"}},
+        {{"E", "P", "M", "I", "A"}, {"E"}},
+        {{"A", "H", "E", "I", "T", "K", "U", "S"},
+            {"H", "E", "T", "K", "S"}},
+        {{"T"}, {"T"}},
+        {{"R", "N", "S", "D", "A", "V", "P", "T", "M", "L", "F"},
+            {"R", "N", "S", "D", "A", "P", "T", "M", "L"}},
+        {{"N", "D", "R", "L", "T"}, {"N", "D", "R", "L", "T"}},
+        {{"I", "E", "U", "S", "O"}, {"E", "S", "O"}},
+        {{"H", "N", "I"}, {"H", "N"}}, {{"E"}, {"E"}},
+        {{"E", "T", "M", "D", "S", "K", "I", "Y", "L", "G", "A", "R", "N",
+             "C"}, {"E", "T", "M", "D", "S", "K", "Y", "A", "N"}},
+        {{"E", "I"}, {"E"}},
+        {{"D", "T", "A", "L"}, {"D", "T", "L"}}, {{"U"}, {"U"}},
+        {{"T", "S", "R", "I"}, {"T", "S", "R"}},
+        {{"T", "N", "L", "C", "I", "M", "D", "S", "R", "P", "G", "B"},
+            {"T", "N", "L", "M", "D", "S", "R"}},
+        {{"O", "E", "A"}, {"E", "A"}},
+        {{"M", "U", "V", "P", "N", "W", "S", "O", "L", "D", "C", "B", "A",
+             "T", "G"}, {"M", "U", "P", "N", "W", "O", "L", "D", "T"}},
+        {{"I", "E", "O", "A"}, {"E", "O"}},
+        {{"H", "E", "T", "I"}, {"H", "E"}},
+        {{"E", "I", "Y", "O", "A"}, {"E", "Y"}},
+        {{"E", "I", "S", "R", "O", "A", "L", "Y", "U", "H"},
+            {"E", "S", "O", "A", "Y", "H"}},
+        {{"D", "T", "I", "C", "G"}, {"D", "T", "G"}},
+        {{"A", "I", "O", "E", "U", "Y"}, {"A", "E", "Y"}},
+        {{"U", "W", "S", "R", "L", "O", "M", "T", "P", "N", "D"},
+            {"U", "W", "R", "L", "O", "M", "T", "P", "N", "D"}},
+        {{"T", "E", "K", "H", "C", "R", "I"}, {"T", "E", "K", "H"}},
+        {{"R", "D", "A", "T"}, {"R", "T"}},
+        {{"R", "L", "E", "V", "S", "N", "A"},
+            {"R", "L", "E", "S", "N", "A"}},
+        {{"L", "N", "T", "R", "U", "S", "M", "P"},
+            {"L", "N", "T", "R", "S", "M"}},
+        {{"E", "O", "I", "A"}, {"E", "O"}},
+        {{"E", "N", "T", "S", "I", "A", "Y", "R", "P", "C"},
+            {"E", "N", "T", "S", "A", "Y"}},
+        {{"S", "N", "D", "T", "W", "V", "R", "L", "F"},
+            {"S", "N", "D", "T", "W", "R", "L"}},
+        {{"R", "T", "S", "N", "L", "I", "C"}, {"R", "T", "S", "N", "L"}},
+        {{"R", "O", "N", "W", "P", "M", "L"},
+            {"R", "O", "N", "W", "P", "M", "L"}},
+        {{"N", "D", "T", "M", "S", "R", "P", "L", "K"},
+            {"N", "D", "T", "M", "S", "R", "P", "L", "K"}},
+        {{"N", "T", "S", "C", "K", "G", "E", "F", "Z", "V", "O", "M", "A"},
+            {"N", "T", "S", "C", "G", "E", "F", "M", "A"}},
+        {{"N", "E", "C", "T", "S", "G", "A", "V", "O", "P", "M", "L", "D",
+             "B"}, {"N", "E", "C", "T", "S", "G", "A", "P", "M", "L", "D"}},
+        {{"H", "G"}, {"H"}}, {{"E", "P", "I", "O", "A"}, {"E"}},
+        {{"E", "I", "S", "A", "U", "O"}, {"E", "S", "O"}},
+        {{"E", "T", "I", "S", "L", "H"}, {"E", "T", "S", "H"}},
+        {{"Y", "E", "O", "I", "S", "A"}, {"Y", "E", "S"}},
+        {{"T", "S", "E", "I", "U", "O", "K", "H"},
+            {"T", "S", "E", "O", "H"}},
+        {{"T", "N", "L", "I", "R", "K", "B", "G", "C"},
+            {"T", "N", "L", "R"}},
+        {{"S", "D", "A", "T", "C", "R", "N", "M", "G", "V", "F"},
+            {"S", "D", "A", "T", "R", "N", "M"}},
+        {{"R", "S", "V", "T", "U", "D"}, {"R", "T", "U", "D"}},
+        {{"R", "U"}, {"R", "U"}},
+        {{"N", "L", "S", "T", "C", "G"}, {"N", "L", "S", "T", "C", "G"}},
+        {{"L", "O", "I"}, {}},
+        {{"L", "Y", "I", "E", "F", "O", "A", "T", "S", "P", "D"},
+            {"L", "Y", "E", "F", "T", "S", "D"}},
+        {{"L", "N", "T"}, {"L", "N", "T"}},
+        {{"L", "T", "R", "N", "M"}, {"L", "T", "R", "N", "M"}},
+        {{"I", "E", "U", "O", "A"}, {"E", "O"}},
+        {{"E", "A", "O"}, {"E", "O"}}, {{"E", "L", "I"}, {"E"}},
+        {{"D", "S", "W", "R", "E", "Y", "V", "T", "L", "C", "A"},
+            {"D", "S", "W", "R", "E", "Y", "T", "L", "A"}},
+        {{"A", "E", "I", "Y", "O"}, {"E", "Y"}},
+        {{"T", "N", "R", "S", "C", "Y", "W", "I", "B"},
+            {"T", "N", "R", "S", "Y", "W"}},
+        {{"T", "E", "S", "I"}, {"T", "E", "S"}},
+        {{"S", "N", "R", "D", "P", "L", "I"},
+            {"S", "N", "R", "D", "P", "L"}},
+        {{"S", "N", "T", "D", "F", "E", "C", "A", "V", "R"},
+            {"S", "N", "T", "D", "F", "E", "C", "A", "R"}},
+        {{"R", "E", "C", "T", "L", "F", "S", "I", "G", "D", "A"},
+            {"R", "E", "T", "L", "S", "D", "A"}},
+        {{"P", "E", "A"}, {"E"}},
+        {{"O", "N", "D", "T", "S", "G", "C", "B", "V", "M", "A"},
+            {"N", "D", "T", "S", "G", "C", "M", "A"}},
+        {{"N", "T", "S", "C", "Z", "O", "G", "F"},
+            {"N", "T", "S", "C", "G", "F"}},
+        {{"N", "E", "S", "I", "A"}, {"N", "E", "S"}},
+        {{"N", "M", "U", "L", "C", "R"}, {"N", "M", "U", "L", "R"}},
+        {{"E", "I"}, {"E"}},
+        {{"E", "A", "I", "O", "U", "R"}, {"E", "O"}},
+        {{"E", "S", "P", "O", "B", "A", "I"}, {"E", "S"}},
+        {{"E", "P", "I", "A", "S", "M"}, {"E", "S"}},
+        {{"D", "N", "L", "S", "R", "E", "C", "T", "V", "A"},
+            {"D", "N", "L", "S", "R", "E", "T", "A"}},
+        {{"T", "I", "E"}, {"T", "E"}},
+        {{"S", "R", "N", "L", "W", "T", "I"}, {"R", "N", "L", "W", "T"}},
+        {{"R", "N", "G", "T"}, {"R", "N", "G", "T"}},
+        {{"P", "T", "I", "C", "A"}, {"T"}}, {{"N"}, {"N"}},
+        {{"H", "T", "K", "E"}, {"H", "T", "K", "E"}},
+        {{"E", "I", "Y", "V", "M", "D"}, {"E", "Y"}},
+        {{"E", "A", "O"}, {"E", "A"}},
+        {{"E", "S", "T", "L", "I"}, {"E", "S", "T"}},
+        {{"E", "S", "L", "T", "R", "I"}, {"E", "S"}},
+        {{"E", "P", "L"}, {"E"}}, {{"E", "O", "I", "A"}, {"E"}},
+        {{"D", "L", "I", "O", "E", "U"}, {"D", "L", "E"}},
+        {{"Y", "T", "R", "N"}, {"Y", "T", "R", "N"}},
+        {{"Y"}, {"Y"}}, {{"Y", "E"}, {"Y", "E"}},
+        {{"W", "N", "O", "S", "C", "V", "U", "T", "R", "P", "G"},
+            {"W", "N", "O", "U", "T", "R", "P"}},
+        {{"U", "T", "R", "O", "D", "A"}, {"U", "T", "R", "O", "D"}},
+        {{"T", "E", "O", "I"}, {"T", "E", "O"}},
+        {{"R", "E", "W", "L", "C", "A"}, {"R", "E", "W", "L", "A"}},
+        {{"R", "N", "C", "E", "L", "G"}, {"R", "N", "C", "E", "L", "G"}},
+        {{"R", "C", "P", "B", "M", "L", "A"}, {"R", "P", "M", "L"}},
+        {{"N", "T", "S", "R", "D"}, {"N", "T", "S", "R", "D"}},
+        {{"L", "O", "A", "T", "R", "E"}, {"T", "E"}},
+        {{"L", "T", "R"}, {"L", "T", "R"}},
+        {{"K", "D", "L", "T", "R", "N", "M"},
+            {"K", "D", "L", "T", "R", "N", "M"}},
+        {{"I", "H", "A", "E", "Y", "U", "S"}, {"H", "A", "E", "Y", "S"}},
+        {{"I", "M", "Y", "N", "L"}, {"M", "Y", "N", "L"}},
+        {{"E", "I", "O", "A"}, {"E", "A"}}, {{"E", "I"}, {"E"}},
+        {{"E"}, {"E"}}, {{"E"}, {"E"}},
+        {{"D", "N", "T", "S", "R", "E"}, {"D", "N", "T", "S", "R", "E"}},
+        {{"C", "R", "M", "I"}, {"R", "M"}},
+        {{"A", "T", "E", "S", "P", "N"}, {"A", "T", "E", "S", "P", "N"}},
+        {{"U"}, {}}, {{"T", "F"}, {"T", "F"}},
+        {{"T", "I", "H", "E", "Y", "W", "S", "A"},
+            {"H", "E", "Y", "S", "A"}},
+        {{"S", "E"}, {"S"}},
+        {{"S", "N", "L", "C"}, {"S", "N", "L"}},
+        {{"S", "N"}, {"S", "N"}}, {{"O", "E", "I"}, {"E"}},
+        {{"O", "E"}, {"O", "E"}},
+        {{"N", "V", "O", "C"}, {"N", "C"}}, {{"N"}, {"N"}},
+        {{"N", "D", "S", "C", "T", "O", "L", "E"},
+            {"N", "D", "S", "C", "T", "L", "E"}},
+        {{"L", "R", "T", "S"}, {"L", "R", "T", "S"}},
+        {{"L", "R", "N"}, {"L", "R", "N"}},
+        {{"I", "U", "E"}, {"E"}}, {{"I", "E", "A"}, {"E"}},
+        {{"I", "H", "E"}, {"H", "E"}}, {{"H", "E"}, {"H", "E"}},
+        {{"F", "T"}, {"F", "T"}}, {{"E", "A", "U", "O"}, {"E"}},
+        {{"E"}, {"E"}}, {{"E", "A"}, {"E"}},
+        {{"E", "O", "R", "L"}, {"E"}}, {{"E", "A"}, {"E"}},
+        {{"C", "S", "R", "A"}, {"S", "R"}},
+        {{"A", "S", "I", "E"}, {"S", "E"}},
+        {{"A", "S", "D"}, {"A", "S", "D"}},
+        {{"Y", "D"}, {"Y", "D"}},
+        {{"W", "N", "M", "E"}, {"W", "N", "M"}},
+        {{"T", "S"}, {"T", "S"}},
+        {{"T", "O", "E", "A"}, {"T", "E"}},
+        {{"S", "C", "R", "N", "L"}, {"S", "R", "N", "L"}},
+        {{"S"}, {"S"}}, {{"S", "E", "I"}, {"S", "E"}},
+        {{"S", "N", "C"}, {"S", "N"}}, {{"R", "I"}, {}},
+        {{"O", "I", "E", "A"}, {"E", "A"}},
+        {{"O", "F", "U", "T", "E"}, {"F", "T", "E"}},
+        {{"O", "E"}, {"O", "E"}}, {{"O"}, {"O"}},
+        {{"N", "I", "T", "R"}, {"N", "T", "R"}},
+        {{"N", "T", "R", "E", "C"}, {"N", "T", "R", "E", "C"}},
+        {{"N"}, {"N"}}, {{"L", "T", "N"}, {"L", "T", "N"}},
+        {{"L", "I", "E"}, {"E"}}, {{"L"}, {}},
+        {{"L", "T", "R", "N"}, {"L", "T", "R", "N"}},
+        {{"K", "I", "E", "C", "A"}, {"K", "E"}},
+        {{"I", "F", "E", "T"}, {"F", "E", "T"}},
+        {{"I", "E", "M", "A"}, {"E", "A"}},
+        {{"I", "E", "Y", "O"}, {"E", "Y"}},
+        {{"H", "R", "O", "I", "A"}, {"H"}}, {{"H"}, {"H"}},
+        {{"E"}, {"E"}}, {{"E"}, {"E"}},
+        {{"E", "O", "I", "A"}, {"E", "A"}},
+        {{"E", "U", "I"}, {"E"}}, {{"E", "O", "I"}, {"E", "O"}},
+        {{"E", "Y", "U"}, {"E", "Y"}}, {{"E", "I"}, {"E"}},
+        {{"E", "I"}, {"E"}}, {{"E"}, {"E"}}, {{"C"}, {}},
+        {{"B", "E"}, {"E"}}, {{"A", "R", "I", "E"}, {"E"}},
+        {{"Y", "E"}, {"Y", "E"}},
+        {{"Y", "O", "I", "E"}, {"Y", "O", "E"}},
+        {{"Y", "A"}, {"Y"}}, {{"V", "T", "O"}, {"T", "O"}},
+        {{"U", "O", "E"}, {"E"}},
+        {{"T", "S", "M", "E", "D"}, {"T", "S", "M", "E"}},
+        {{"T", "R", "D"}, {"T", "R", "D"}},
+        {{"T", "R", "L", "B"}, {"T", "R", "L"}},
+        {{"T", "R", "L"}, {"T", "R", "L"}}, {{"T"}, {"T"}},
+        {{"T"}, {"T"}},
+        {{"S", "R", "N", "M"}, {"S", "R", "N", "M"}},
+        {{"S"}, {"S"}}, {{"S"}, {"S"}}, {{"S"}, {"S"}},
+        {{"R", "P"}, {"R", "P"}}, {{"P"}, {}}, {{"P", "O"}, {}},
+        {{"O", "E"}, {"E"}}, {{"O"}, {}}, {{"O"}, {}},
+        {{"O"}, {}}, {{"N"}, {}}, {{"M"}, {"M"}},
+        {{"M"}, {"M"}}, {{"L"}, {}}, {{"L"}, {"L"}},
+        {{"I"}, {}}, {{"I"}, {}}, {{"I", "E"}, {"E"}},
+        {{"I"}, {}}, {{"I", "E"}, {"E"}}, {{"I"}, {}},
+        {{"H"}, {}}, {{"H", "E"}, {"H", "E"}}, {{"H"}, {"H"}},
+        {{"F"}, {"F"}}, {{"E"}, {}}, {{"E"}, {"E"}},
+        {{"E"}, {}}, {{"E"}, {"E"}}, {{"E", "A"}, {"E"}},
+        {{"E"}, {"E"}}, {{"E"}, {"E"}}, {{"E"}, {"E"}},
+        {{"E"}, {"E"}}, {{"E"}, {"E"}}, {{"E"}, {"E"}},
+        {{"E"}, {"E"}}, {{"E"}, {"E"}}, {{"E"}, {"E"}},
+        {{"E"}, {"E"}}, {{"E"}, {"E"}}, {{"E"}, {"E"}},
+        {{"D"}, {"D"}}, {{"A"}, {}}, {{"A"}, {}}};
+    // ------------------------------------------------------------------------
+    randomWord = startBiGram[indexGenerator(startBiGram.length)];
+    int flag = 0;
+    int count = 0;
+    String previousWord;
+    while (randomWord.length() != wordLength) {
+      previousWord = randomWord;
+      randomWord = addCharacter(startBiGram, wordLength, randomWord,
+          lookupBiGram, nextCharLookup, flag);
+      if (previousWord.equals(randomWord)) {
+        count++;
+      } else {
+        flag = 0;
+      }
+      if (count == 5) {
+        flag = 1;
+        count++;
+      } else if (count == 20) {
+        randomWord = startBiGram[indexGenerator(startBiGram.length)];
+        count = 0;
+      }
+    }
+    return randomWord;
+  }
+
+  private static String addCharacter(String[] startBiGram, int desiredLength,
+      String currentWord, String[] lookupBiGram, String[][][] nextCharLookup,
+      int flag) {
+    int mainIndex = getLookupIndex(currentWord, lookupBiGram);
+    int type = 0;
+    if (currentWord.length() == (desiredLength - 1)) {
+      type = 1;
+    }
+    while (mainIndex < 0 || mainIndex > 263
+        || nextCharLookup[mainIndex][type].length <= 0) {
+      if (currentWord.length() == 2) {
+        return startBiGram[indexGenerator(startBiGram.length)];
+      }
+      if (flag == 1) {
+        currentWord = backtrack(currentWord, 2);
+        flag = 0;
+      } else {
+        currentWord = backtrack(currentWord, 1);
+      }
+      mainIndex = getLookupIndex(currentWord, lookupBiGram);
+      if (type == 1) {
+        type = 0;
+      }
+    }
+    String updatedWord = currentWord
+        + getNextCharacter(type, mainIndex, nextCharLookup);
+    return updatedWord;
+  }
+
+  private static int indexGenerator(int arrayLength) {
+    int theIndex;
+    Random generator = new Random();
+    theIndex = generator.nextInt(arrayLength);
+    return theIndex;
+  }
+
+  private static String getNextCharacter(int type, int mainIndex,
+      String[][][] theCharacterVault) {
+    String nextChar;
+    int i = indexGenerator(theCharacterVault[mainIndex][type].length);
+    nextChar = theCharacterVault[mainIndex][type][i];
+    return nextChar;
+  }
+
+  private static String backtrack(String theWord, int numberChars) {
+    theWord = theWord.substring(0, theWord.length() - numberChars);
+    return theWord;
+  }
+
+  private static int getLookupIndex(String theWord, String[] lookupArray) {
+    String lookupCharacters = theWord.substring(theWord.length() - 2);
+    int lookupIndex = Arrays.asList(lookupArray).indexOf(lookupCharacters);
+    return lookupIndex;
+  }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/utils/WordLengthException.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/utils/WordLengthException.java
new file mode 100644
index 0000000..42a5f7f
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/utils/WordLengthException.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.yarn.appcatalog.utils;
+
+/**
+ * Word length exception class.
+ */
+public class WordLengthException extends Exception {
+  private static final long serialVersionUID = -217354336577036950L;
+
+  public WordLengthException(String message){
+    super(message);
+  }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/utils/package-info.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/utils/package-info.java
new file mode 100644
index 0000000..bde7fc5
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/java/org/apache/hadoop/yarn/appcatalog/utils/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ *
+ */
+/**
+ * Application Catalog Utilities classes.
+ */
+package org.apache.hadoop.yarn.appcatalog.utils;
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/app.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/app.js
new file mode 100644
index 0000000..0a7b6db
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/app.js
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+var app = angular.module('app', [
+   'ngRoute',
+   'filters',
+   'controllers'
+]);
+
+app.directive('jsonText', function() {
+  return {
+      restrict: 'A',
+      require: 'ngModel',
+      link: function(scope, element, attr, ngModel) {
+        function into(input) {
+          console.log(JSON.parse(input));
+          return JSON.parse(input);
+        }
+        function out(data) {
+          return JSON.stringify(data);
+        }
+        ngModel.$parsers.push(into);
+        ngModel.$formatters.push(out);
+      }
+  };
+});
+
+app.config(['$routeProvider',
+  function ($routeProvider) {
+    $routeProvider.when('/', {
+      templateUrl: 'partials/home.html',
+      controller: 'AppStoreController'
+    }).when('/app/:id', {
+      templateUrl: 'partials/details.html',
+      controller: 'AppDetailsController'
+    }).when('/new', {
+      templateUrl: 'partials/new.html',
+      controller: 'NewAppController'
+    }).when('/deploy/:id', {
+      templateUrl: 'partials/deploy.html',
+      controller: 'DeployAppController'
+    }).otherwise({
+      redirectTo: '/'
+    });
+}]);
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/controllers.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/controllers.js
new file mode 100644
index 0000000..241f15d
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/controllers.js
@@ -0,0 +1,320 @@
+/*
+ * 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.
+ */
+var controllers = angular.module("controllers", []);
+
+controllers.controller("AppListController", [ '$scope', '$rootScope', '$http',
+    function($scope, $rootScope, $http) {
+      $scope.appList = [];
+
+      function successCallback(response) {
+        $scope.appList = response.data;
+        $rootScope.$emit("hideLoadScreen", {});
+      }
+
+      function errorCallback(response) {
+        $rootScope.$emit("hideLoadScreen", {});
+        console.log("Error in downloading application list");
+      }
+
+      $rootScope.$on("RefreshAppList", function() {
+        $scope.refreshList();
+      });
+
+      $scope.refreshList = function() {
+        $http({
+          method : 'GET',
+          url : '/v1/app_list'
+        }).then(successCallback, errorCallback);
+      }
+
+      $scope.deleteApp = function(id, name) {
+        $rootScope.$emit("showLoadScreen", {});
+        $http({
+          method: 'DELETE',
+          url: '/v1/app_list/' + id + '/' + name
+        }).then(function(response) {
+          $rootScope.$emit("RefreshAppList", {});
+          window.location = '/#';
+        }, function(response) {
+          console.log(response);
+        });
+      }
+      $http({
+        method : 'GET',
+        url : '/v1/app_list'
+      }).then(successCallback, errorCallback);
+    } ]);
+
+controllers.controller("AppStoreController", [ '$scope', '$rootScope', '$http',
+    function($scope, $rootScope, $http) {
+      $scope.canDeployApp = function() {
+        return false;
+      };
+      $scope.appStore = [];
+      $scope.searchText = null;
+
+      function successCallback(response) {
+        $scope.appStore = response.data;
+      }
+
+      function errorCallback(response) {
+        console.log("Error in downloading AppStore information.");
+      }
+
+      $scope.deployApp = function(id) {
+        window.location = '/#!/deploy/' + id;
+      }
+
+      $http({
+        method : 'GET',
+        url : '/v1/app_store/recommended'
+      }).then(successCallback, errorCallback);
+
+      $scope.change = function(text) {
+        var q = $scope.searchText;
+        $http({
+          method : 'GET',
+          url : '/v1/app_store/search?q=' + q
+        }).then(successCallback, errorCallback);
+      }
+    } ]);
+
+controllers.controller("AppDetailsController", [ '$scope', '$interval', '$rootScope', '$http',
+    '$routeParams', function($scope, $interval, $rootScope, $http, $routeParams) {
+      $scope.details = {"yarnfile":{"state":"UNKNOWN"}};
+      $scope.appName = $routeParams.id;
+      var timer = $interval(function() {
+        $scope.refreshAppDetails();
+      }, 2000);
+
+      $scope.refreshAppDetails = function() {
+        $http({
+          method : 'GET',
+          url : '/v1/app_details/status/' + $scope.appName
+        }).then(successCallback, errorCallback);
+      }
+
+      $scope.stopApp = function(id) {
+        $http({
+          method : 'POST',
+          url : '/v1/app_details/stop/' + id
+        }).then(function(data, status, header, config) {
+          $scope.refreshAppDetails();
+        }, errorCallback);
+      }
+
+      $scope.restartApp = function(id) {
+        $http({
+          method : 'POST',
+          url : '/v1/app_details/restart/' + id
+        }).then(function(data, status, header, config) {
+          $scope.refreshAppDetails();
+        }, errorCallback);
+      }
+
+      $scope.canDeployApp = function() {
+        return true;
+      };
+
+      $scope.checkServiceLink = function() {
+        if ($scope.details.yarnfile.state != "STABLE") {
+          return true;
+        } else {
+          return false;
+        }
+      }
+
+      function successCallback(response) {
+        if (response.data.yarnfile.components.length!=0) {
+          $scope.details = response.data;
+        } else {
+          // When application is in accepted or failed state, it does not
+          // have components detail, hence we update states only.
+          $scope.details.yarnfile.state = response.data.yarnfile.state;
+        }
+      }
+
+      function errorCallback(response) {
+        console.log("Error in getting application detail");
+      }
+
+      $rootScope.$on("RefreshAppDetails", function() {
+        $scope.refreshAppDetails();
+      });
+
+      $scope.$on("$locationChangeStart", function() {
+        $interval.cancel(timer);
+      });
+
+      $scope.$on('$destroy', function() {
+        $interval.cancel(timer);
+      });
+
+      $http({
+        method : 'GET',
+        url : '/v1/app_details/config/' + $scope.appName
+      }).then(successCallback, errorCallback);
+
+    } ]);
+
+controllers.controller("NewAppController", [ '$scope', '$rootScope', '$http', function($scope, $rootScope, $http) {
+    $scope.details = {
+        "name" : "",
+        "version" : "",
+        "organization" : "",
+        "description" : "",
+        "quicklinks": {
+          "UI": "http://${SERVICE_NAME}.${USER}.${DOMAIN}:8080/"
+        },
+        "icon" : "",
+        "components" : [
+          {
+            "name" : "",
+            "number_of_containers" : 1,
+            "artifact" : {
+              "id": "centos:latest"
+            },
+            "launch_command": "",
+            "resource" : {
+              "cpus" : 1,
+              "memory" : 2048
+            },
+            "run_privileged_container" : false,
+            "dependencies" : [],
+            "placement_policy" : {
+              "constraints" : []
+            },
+            "configuration" : {
+              "env" : {
+                "YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE":"true"
+              },
+              "properties" : {
+                "docker.network":"host"
+              }
+            }
+          }
+        ]
+    };
+
+    $scope.template = {
+        "name" : "",
+        "number_of_containers" : 1,
+        "artifact" : {
+          "id": "centos:latest"
+        },
+        "launch_command": "",
+        "resource" : {
+          "cpus" : 1,
+          "memory" : 2048
+        },
+        "run_privileged_container" : false,
+        "dependencies" : [],
+        "placement_policy" : {
+          "constraints" : []
+        },
+        "configuration" : {
+          "env" : {
+            "YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE":"true"
+          },
+          "properties" : {
+            "docker.network":"host"
+          }
+        }
+    };
+
+    $scope.message = null;
+    $scope.error = null;
+
+    $scope.save = function() {
+      $http({
+        method : 'POST',
+        url : '/v1/app_store/register',
+        data : JSON.stringify($scope.details)
+      }).then(successCallback, errorCallback)
+    }
+
+    $scope.add = function() {
+      $scope.details.components.push($scope.template);
+    }
+
+    $scope.remove = function(index) {
+      $scope.details.components.splice(index, 1);
+    }
+
+    function successCallback(response) {
+      $scope.message = "Application published successfully.";
+      setTimeout(function() {
+        $scope.$apply(function() {
+          window.location = '/#';
+        });
+      }, 5000);
+    }
+
+    function errorCallback(response) {
+      $scope.error = "Error in registering application configuration.";
+    }
+
+    } ]);
+
+controllers.controller("DeployAppController", [ '$scope', '$rootScope', '$http',
+    '$routeParams', function($scope, $rootScope, $http, $routeParams) {
+    $scope.id = $routeParams.id;
+
+    function successCallback(response) {
+      $scope.details = response.data;
+      $rootScope.$emit("hideLoadScreen", {});
+    }
+
+    function errorCallback(response) {
+      $rootScope.$emit("hideLoadScreen", {});
+      console.log("Error in downloading application template.");
+    }
+
+    $scope.launchApp = function(app) {
+      $rootScope.$emit("showLoadScreen", {});
+      $http({
+        method : 'POST',
+        url : '/v1/app_list/' + $scope.id,
+        data : JSON.stringify($scope.details.app)
+      }).then(function(data, status, headers, config) {
+        $rootScope.$emit("RefreshAppList", {});
+        window.location = '/#!/app/' + data.data.id;
+      }, function(data, status, headers, config) {
+        console.log('error', data, status);
+      });
+    }
+
+    $http({
+      method : 'GET',
+      url : '/v1/app_store/get/' + $scope.id
+    }).then(successCallback, errorCallback);
+
+}]);
+
+controllers.controller("LoadScreenController", [ '$scope', '$rootScope', '$http', function($scope, $rootScope, $http) {
+  $scope.loadScreen = "hide";
+
+  $rootScope.$on("showLoadScreen", function() {
+    $scope.loadScreen = "show";
+  });
+
+  $rootScope.$on("hideLoadScreen", function() {
+    $scope.loadScreen = "hide";
+  });
+
+}]);
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/filters.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/filters.js
new file mode 100644
index 0000000..bfb6838
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/filters.js
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+var app = angular.module("filters", []);
+
+app.filter("counterValue",function(){
+  return function(value){
+    var count=parseInt(value), suffix="";
+    if (count>=1000000){
+      count=Math.round(count/1000000);
+      suffix="M"
+    } else if (count>=1000){
+      count=Math.round(count/1000);
+      suffix="K"
+    }
+    return""+count+suffix
+  }
+});
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/routes.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/routes.js
new file mode 100644
index 0000000..d551913
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/routes.js
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/services.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/services.js
new file mode 100644
index 0000000..d551913
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/javascript/services.js
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/resources/appcatalog.properties b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/resources/appcatalog.properties
new file mode 100644
index 0000000..443b108
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/resources/appcatalog.properties
@@ -0,0 +1 @@
+solr_url=http://localhost:8983/solr/appcatalog/
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/resources/log4j.properties b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/resources/log4j.properties
new file mode 100644
index 0000000..9a0c608
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/resources/log4j.properties
@@ -0,0 +1,23 @@
+#   Licensed 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.
+
+log4j.rootLogger = INFO, CATALINA
+
+# Define all the appenders
+log4j.appender.CATALINA = org.apache.log4j.DailyRollingFileAppender
+log4j.appender.CATALINA.File = ${catalina.base}/logs/appcatalog.log
+log4j.appender.CATALINA.Append = true
+log4j.appender.CATALINA.Encoding = UTF-8
+# Roll-over the log once per day
+log4j.appender.CATALINA.DatePattern = '.'yyyy-MM-dd'.log'
+log4j.appender.CATALINA.layout = org.apache.log4j.PatternLayout
+log4j.appender.CATALINA.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/.gitignore b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/.gitignore
new file mode 100644
index 0000000..a725465
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/.gitignore
@@ -0,0 +1 @@
+vendor/
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/WEB-INF/beans.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/WEB-INF/beans.xml
new file mode 100644
index 0000000..3326fa1
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/WEB-INF/beans.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+-->
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
+       bean-discovery-mode="annotated">
+</beans>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/WEB-INF/web.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..fac7c5b
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ 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.
+-->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+   version="3.0">
+
+    <context-param>
+      <param-name>local-deployment</param-name>
+      <param-value>true</param-value>
+    </context-param>
+
+
+    <description>
+      YARN Application Catalog
+    </description>
+    <display-name>appcatalog</display-name>
+
+    <servlet>
+      <servlet-name>REST_API</servlet-name>
+      <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+      <init-param>
+        <param-name>com.sun.jersey.config.property.packages</param-name>
+        <param-value>org.apache.hadoop.yarn.appcatalog.controller;com.wordnik.swagger.jaxrs.listing;com.wordnik.swagger.jaxrs.json</param-value>
+      </init-param>
+      <init-param>
+        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
+        <param-value>true</param-value>
+      </init-param>
+      <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet>
+      <servlet-name>DefaultJaxrsConfig</servlet-name>
+      <servlet-class>com.wordnik.swagger.jaxrs.config.DefaultJaxrsConfig</servlet-class>
+      <init-param>
+        <param-name>api.version</param-name>
+        <param-value>3</param-value>
+      </init-param>
+      <init-param>
+        <param-name>swagger.api.basepath</param-name>
+        <param-value>http://localhost:8080/v1</param-value>
+      </init-param>
+      <load-on-startup>2</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+      <servlet-name>REST_API</servlet-name>
+      <url-pattern>/v1/*</url-pattern>
+    </servlet-mapping>
+
+    <filter>
+       <filter-name>CorsFilter</filter-name>
+       <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
+     </filter>
+     <filter-mapping>
+       <filter-name>CorsFilter</filter-name>
+       <url-pattern>/*</url-pattern>
+     </filter-mapping>
+
+</web-app>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/bootstrap-hadoop.css b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/bootstrap-hadoop.css
new file mode 100644
index 0000000..5aa6e46
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/bootstrap-hadoop.css
@@ -0,0 +1,1488 @@
+/**
+ * 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.
+ */
+
+@font-face {
+  font-family: 'Roboto';
+  font-weight: normal;
+  font-style: normal;
+  src: url('../vendor/roboto-fontface/fonts/roboto/Roboto-Regular.woff') format('woff');
+}
+.font-mixin {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+}
+.btn,
+.btn:focus {
+  outline: none;
+  font-family: 'Roboto', sans-serif;
+  text-transform: uppercase;
+  height: 34px;
+  font-size: 14px;
+  padding: 10px 20px;
+  line-height: 14px;
+}
+.btn .glyphicon,
+.btn:focus .glyphicon {
+  top: -1px;
+  float: left;
+}
+.box-shadow {
+  box-shadow: 0 0 2px 0 #1391c1;
+}
+.btn-disabled {
+  opacity: 0.6;
+  box-shadow: none;
+}
+.btn-default-disabled {
+  opacity: 0.6;
+  box-shadow: none;
+  color: #FFF;
+  background-color: #808793;
+  border: none;
+}
+.btn-default,
+.btn-default:focus {
+  color: #666;
+  background-color: #FFF;
+  border: 1px solid #CFD3D7;
+}
+.btn-default:hover,
+.btn-default:focus:hover {
+  color: #FFF;
+  background-color: #808793;
+}
+.btn-default:active,
+.btn-default:focus:active {
+  color: #666;
+  background-color: #FFF;
+  border: 1px solid #CFD3D7;
+  box-shadow: 0 0 2px 0 #1391c1;
+}
+.btn-default[disabled],
+.btn-default:focus[disabled],
+.btn-default.disabled,
+.btn-default:focus.disabled {
+  opacity: 0.6;
+  box-shadow: none;
+  color: #FFF;
+  background-color: #808793;
+  border: none;
+}
+.btn-default[disabled]:active,
+.btn-default:focus[disabled]:active,
+.btn-default.disabled:active,
+.btn-default:focus.disabled:active,
+.btn-default[disabled].active,
+.btn-default:focus[disabled].active,
+.btn-default.disabled.active,
+.btn-default:focus.disabled.active,
+.btn-default[disabled]:hover,
+.btn-default:focus[disabled]:hover,
+.btn-default.disabled:hover,
+.btn-default:focus.disabled:hover {
+  opacity: 0.6;
+  box-shadow: none;
+  color: #FFF;
+  background-color: #808793;
+  border: none;
+}
+.btn-primary-disabled {
+  opacity: 0.6;
+  box-shadow: none;
+  color: #D1E8D1;
+  background-color: #3FAE2A;
+  border: 1px solid #3FAE2A;
+}
+.btn-primary,
+.btn-primary:focus {
+  color: #FFF;
+  background-color: #3FAE2A;
+  border: 1px solid #3FAE2A;
+}
+.btn-primary:hover,
+.btn-primary:focus:hover {
+  color: #FFF;
+  background-color: #429929;
+  border: 1px solid #429929;
+}
+.btn-primary:active,
+.btn-primary:focus:active,
+.btn-primary.active,
+.btn-primary:focus.active {
+  color: #FFF;
+  background-color: #3FAE2A;
+  border: 1px solid #3FAE2A;
+  box-shadow: 0 0 2px 0 #1391c1;
+}
+.btn-primary[disabled],
+.btn-primary:focus[disabled],
+.btn-primary.disabled,
+.btn-primary:focus.disabled {
+  opacity: 0.6;
+  box-shadow: none;
+  color: #D1E8D1;
+  background-color: #3FAE2A;
+  border: 1px solid #3FAE2A;
+}
+.btn-primary[disabled]:active,
+.btn-primary:focus[disabled]:active,
+.btn-primary.disabled:active,
+.btn-primary:focus.disabled:active,
+.btn-primary[disabled].active,
+.btn-primary:focus[disabled].active,
+.btn-primary.disabled.active,
+.btn-primary:focus.disabled.active,
+.btn-primary[disabled]:hover,
+.btn-primary:focus[disabled]:hover,
+.btn-primary.disabled:hover,
+.btn-primary:focus.disabled:hover {
+  opacity: 0.6;
+  box-shadow: none;
+  color: #D1E8D1;
+  background-color: #3FAE2A;
+  border: 1px solid #3FAE2A;
+}
+.btn-secondary-disabled {
+  opacity: 0.6;
+  box-shadow: none;
+  color: #D1E8D1;
+  background-color: #429929;
+  border: 1px solid #3FAE2A;
+}
+.btn-secondary,
+.btn-secondary:focus {
+  color: #429929;
+  background-color: #FFF;
+  border: 1px solid #3FAE2A;
+}
+.btn-secondary:hover,
+.btn-secondary:focus:hover {
+  color: #FFF;
+  background-color: #429929;
+}
+.btn-secondary:active,
+.btn-secondary:focus:active {
+  color: #429929;
+  background-color: #FFF;
+  box-shadow: 0 0 2px 0 #1391c1;
+}
+.btn-secondary[disabled],
+.btn-secondary:focus[disabled],
+.btn-secondary.disabled,
+.btn-secondary:focus.disabled {
+  opacity: 0.6;
+  box-shadow: none;
+  color: #D1E8D1;
+  background-color: #429929;
+  border: 1px solid #3FAE2A;
+}
+.btn-secondary[disabled]:active,
+.btn-secondary:focus[disabled]:active,
+.btn-secondary.disabled:active,
+.btn-secondary:focus.disabled:active,
+.btn-secondary[disabled].active,
+.btn-secondary:focus[disabled].active,
+.btn-secondary.disabled.active,
+.btn-secondary:focus.disabled.active,
+.btn-secondary[disabled]:hover,
+.btn-secondary:focus[disabled]:hover,
+.btn-secondary.disabled:hover,
+.btn-secondary:focus.disabled:hover {
+  opacity: 0.6;
+  box-shadow: none;
+  color: #D1E8D1;
+  background-color: #429929;
+  border: 1px solid #3FAE2A;
+}
+.btn-success {
+  border: none;
+}
+.btn-regular-default-state {
+  background-color: #FFF;
+  color: #666;
+  border: 1px solid #cfd3d7;
+}
+.btn-primary-default-state {
+  background-color: #3FAE2A;
+  border: 1px solid #3FAE2A;
+  color: #FFF;
+}
+.btn-group.open .btn.dropdown-toggle,
+.dropdown.open .btn.dropdown-toggle {
+  box-shadow: inset 0px 0px 3px 0px #1391c1;
+}
+.btn-group.open .btn.dropdown-toggle,
+.dropdown.open .btn.dropdown-toggle,
+.btn-group.open .btn.dropdown-toggle.btn-default,
+.dropdown.open .btn.dropdown-toggle.btn-default {
+  background-color: #FFF;
+  color: #666;
+  border: 1px solid #cfd3d7;
+}
+.btn-group.open .btn.dropdown-toggle:hover,
+.dropdown.open .btn.dropdown-toggle:hover,
+.btn-group.open .btn.dropdown-toggle.btn-default:hover,
+.dropdown.open .btn.dropdown-toggle.btn-default:hover {
+  background-color: #FFF;
+  color: #666;
+  border: 1px solid #cfd3d7;
+}
+.btn-group.open .btn.dropdown-toggle + .dropdown-menu > li > a:hover,
+.dropdown.open .btn.dropdown-toggle + .dropdown-menu > li > a:hover,
+.btn-group.open .btn.dropdown-toggle.btn-default + .dropdown-menu > li > a:hover,
+.dropdown.open .btn.dropdown-toggle.btn-default + .dropdown-menu > li > a:hover {
+  background-color: #808793;
+  color: #FFF;
+}
+.btn-group.open .btn.dropdown-toggle.btn-primary,
+.dropdown.open .btn.dropdown-toggle.btn-primary {
+  background-color: #3FAE2A;
+  border: 1px solid #3FAE2A;
+  color: #FFF;
+}
+.btn-group.open .btn.dropdown-toggle.btn-primary:hover,
+.dropdown.open .btn.dropdown-toggle.btn-primary:hover {
+  background-color: #3FAE2A;
+  border: 1px solid #3FAE2A;
+  color: #FFF;
+}
+.btn-group.open .btn.dropdown-toggle.btn-primary + .dropdown-menu > li > a:hover,
+.dropdown.open .btn.dropdown-toggle.btn-primary + .dropdown-menu > li > a:hover {
+  background-color: #429929;
+  color: #FFF;
+}
+.btn-group.open .dropdown-menu,
+.dropdown.open .dropdown-menu {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  border-radius: 2px;
+  font-size: 14px;
+  min-width: 200px;
+  background: #FFF;
+  color: #666;
+  border: 1px solid #cfd3d7;
+}
+.btn-group.open .dropdown-menu > li,
+.dropdown.open .dropdown-menu > li {
+  margin-bottom: 1px;
+}
+.btn-group.open .dropdown-menu > li > a,
+.dropdown.open .dropdown-menu > li > a {
+  height: 24px;
+}
+.btn-group .btn.dropdown-toggle:first-child,
+.dropdown .btn.dropdown-toggle:first-child {
+  min-width: 80px;
+}
+.btn-group .btn.dropdown-toggle.disabled,
+.dropdown .btn.dropdown-toggle.disabled,
+.btn-group .btn.dropdown-toggle[disabled],
+.dropdown .btn.dropdown-toggle[disabled] {
+  opacity: 0.6;
+}
+input.form-control {
+  font-size: 14px;
+  border-radius: 2px;
+  color: #666;
+  border: 1px solid #CFD3D7;
+  height: 34px;
+  padding: 10px;
+}
+input.form-control:focus {
+  border-color: #1291c1;
+  box-shadow: none;
+}
+.help-block {
+  color: #999999;
+  font-size: 14px;
+}
+.help-block.validation-block {
+  color: #999999;
+  margin-top: 10px;
+}
+.help-block.validation-block::before {
+  position: relative;
+  top: 2px;
+  margin-right: 5px;
+  font-family: 'Glyphicons Halflings';
+}
+.has-success input.form-control {
+  color: #666;
+  border: 1px solid #1EB475;
+}
+.has-success input.form-control:focus {
+  border-color: #1EB475;
+  box-shadow: none;
+}
+.has-success .help-block.validation-block::before {
+  content: '\e084';
+  color: #1EB475;
+}
+.has-error input.form-control {
+  color: #666;
+  border: 1px solid #EF6162;
+}
+.has-error input.form-control:focus {
+  border-color: #EF6162;
+  box-shadow: none;
+}
+.has-error .help-block.validation-block::before {
+  content: '\e083';
+  color: #EF6162;
+}
+.has-warning input.form-control {
+  color: #666;
+  border: 1px solid #E98A40;
+}
+.has-warning input.form-control:focus {
+  border-color: #E98A40;
+  box-shadow: none;
+}
+.has-warning .help-block.validation-block::before {
+  content: '\e101';
+  color: #E98A40;
+}
+.form-control[disabled],
+.form-control[readonly],
+fieldset[disabled] .form-control {
+  color: #999999;
+  border-color: #cccccc;
+  background-color: #dddddd;
+}
+h2.table-title {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  margin-top: 10px;
+  font-size: 20px;
+}
+.table {
+  color: #666;
+  font-size: 13px;
+}
+.table thead,
+.table tfoot {
+  color: #999;
+}
+.table input[type="checkbox"] + label {
+  position: relative;
+  line-height: 1.3em;
+  font-size: initial;
+  top: 4px;
+  margin-bottom: 0;
+}
+.table thead > tr > th {
+  border-bottom-color: #EEE;
+}
+.table tfoot > tr:first-of-type > td {
+  border-top-width: 2px;
+  border-top-color: #EEE;
+}
+.table > tbody > tr > td {
+  border-top-color: #EEE;
+}
+.table > tbody > tr.active {
+  background-color: #EEE;
+}
+.table > tbody > tr.active > td {
+  background-color: #EEE;
+}
+.table.table-hover .action {
+  visibility: hidden;
+  padding: 0;
+  line-height: 1;
+}
+.table.table-hover .action:hover {
+  text-decoration: none;
+}
+.table.table-hover > tbody > tr {
+  border-width: 0 1px 1px;
+  border-style: solid;
+  border-color: #EEE transparent;
+}
+.table.table-hover > tbody > tr > td {
+  border-width: 0;
+}
+.table.table-hover > tbody > tr:hover {
+  border-color: #A7DFF2;
+  background-color: #E7F6FC;
+}
+.table.table-hover > tbody > tr:hover > td {
+  border-top: 1px solid #A7DFF2;
+  background-color: #E7F6FC;
+}
+.table.table-hover > tbody > tr:hover > td .action {
+  visibility: visible;
+}
+.table.table-hover > tbody > tr:first-of-type > td {
+  border-top: 1px solid transparent;
+}
+.table.table-hover > tbody > tr:first-of-type:hover > td {
+  border-color: #A7DFF2;
+}
+.pagination-block .pagination-block-item {
+  float: left;
+  padding: 0 5px;
+}
+.pagination-block .pagination-block-item a,
+.pagination-block .pagination-block-item a:visited,
+.pagination-block .pagination-block-item a:focus {
+  text-decoration: none;
+}
+.pagination-block .pagination-block-item select {
+  border: none;
+  background-color: transparent;
+  color: #1491C1;
+}
+.nav.nav-tabs {
+  border: none;
+  margin-bottom: 20px;
+}
+.nav.nav-tabs li a {
+  border-width: 0;
+  border-radius: 0;
+  border-bottom: 2px solid transparent;
+  color: #666;
+  text-transform: uppercase;
+}
+.nav.nav-tabs li a:hover,
+.nav.nav-tabs li a:active,
+.nav.nav-tabs li a:focus {
+  color: #333;
+  border-top-width: 0;
+  border-left-width: 0;
+  border-right-width: 0;
+  background: none;
+}
+.nav.nav-tabs li a .badge.badge-important {
+  display: inline;
+}
+.nav.nav-tabs li.active a {
+  color: #333;
+  border-bottom: 2px solid #3FAE2A;
+}
+.nav-tabs-left li,
+.nav-tabs-right li {
+  float: none;
+  margin-bottom: 2px;
+}
+.nav-tabs-left li a,
+.nav-tabs-right li a {
+  margin-right: 0;
+}
+.nav-tabs-left li {
+  margin-right: -1px;
+}
+.nav-tabs-left li a {
+  border: 2px solid transparent !important;
+}
+.nav-tabs-left li.active a,
+.nav-tabs-left li.active a:hover,
+.nav-tabs-left li.active a:active,
+.nav-tabs-left li.active a:focus {
+  border-right: 2px solid #3FAE2A !important;
+}
+.nav-tabs-right li {
+  margin-left: -1px;
+}
+.nav-tabs-right li a {
+  border: 2px solid transparent !important;
+}
+.nav-tabs-right li.active a,
+.nav-tabs-right li.active a:hover,
+.nav-tabs-right li.active a:active,
+.nav-tabs-right li.active a:focus {
+  border-left: 2px solid #3FAE2A !important;
+}
+.wizard {
+  border: 2px solid #ebecf1;
+}
+.wizard .wizard-header h3 {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  font-size: 20px;
+  color: #333;
+  margin: 15px 20px;
+}
+.wizard .wizard-body {
+  overflow: hidden;
+  margin: 0;
+}
+.wizard .wizard-body .wizard-content {
+  background: #ebecf1;
+  padding-top: 25px;
+  float: left;
+  margin-bottom: -99999px;
+  padding-bottom: 99999px;
+}
+.wizard .wizard-body .wizard-content .step-title {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-weight: bold;
+  font-size: 18px;
+  color: #666;
+}
+.wizard .wizard-body .wizard-content .step-description {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-size: 14px;
+  line-height: 1.4;
+  color: #999;
+}
+.wizard .wizard-body .wizard-content .panel.panel-default {
+  border: none;
+  box-shadow: none;
+  margin-top: 20px;
+}
+.wizard .wizard-body .wizard-content .panel.panel-default .panel-body {
+  padding: 30px 20px;
+}
+.wizard .wizard-body .wizard-nav {
+  min-height: 550px;
+  padding-top: 25px;
+  background-color: #323544;
+  float: left;
+  margin-bottom: -99999px;
+  padding-bottom: 99999px;
+}
+.wizard .wizard-body .wizard-nav .nav li {
+  padding: 0px 15px;
+}
+.wizard .wizard-body .wizard-nav .nav li a {
+  height: 48px;
+  padding: 0px 5px;
+  display: table-cell;
+  vertical-align: middle;
+}
+.wizard .wizard-body .wizard-nav .nav li .step-marker {
+  position: absolute;
+  top: 9px;
+  line-height: 16px;
+  text-align: center;
+  width: 20px;
+  height: 20px;
+  border: 2px solid #1EB475;
+  border-radius: 50%;
+  font-size: 12px;
+  font-style: inherit;
+  color: #1EB475;
+  background-color: #323544;
+}
+.wizard .wizard-body .wizard-nav .nav li .step-name {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-size: 14px;
+  color: #999;
+  margin-left: 30px;
+}
+.wizard .wizard-body .wizard-nav .nav li .step-index {
+  line-height: 18px;
+}
+.wizard .wizard-body .wizard-nav .nav li .step-description {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-size: 12px;
+  color: #999;
+  margin-left: 30px;
+}
+.wizard .wizard-body .wizard-nav .nav li.completed .step-marker {
+  background-color: #1EB475;
+  color: white;
+  font-size: 10px;
+  padding-left: 2px;
+}
+.wizard .wizard-body .wizard-nav .nav li.completed .step-marker .step-index {
+  display: none;
+}
+.wizard .wizard-body .wizard-nav .nav li.completed .step-marker:after {
+  font-family: "Glyphicons Halflings";
+  content: "\e013";
+  position: relative;
+  top: 1px;
+  left: -1px;
+}
+.wizard .wizard-body .wizard-nav .nav li.completed:after {
+  width: 2px;
+  height: 100%;
+  position: absolute;
+  background-color: #1EB475;
+  content: "";
+  top: 25px;
+  left: 29px;
+}
+.wizard .wizard-body .wizard-nav .nav li.completed:last-child:after {
+  content: none;
+}
+.wizard .wizard-body .wizard-nav .nav li.active .step-name {
+  font-weight: bold;
+}
+.wizard .wizard-body .wizard-nav .nav li.disabled .step-marker {
+  color: #666;
+  border-color: #666;
+}
+.wizard .wizard-body .wizard-nav .nav li.disabled .step-name,
+.wizard .wizard-body .wizard-nav .nav li.disabled .step-description {
+  color: #666;
+}
+.wizard .wizard-body .wizard-nav .nav li.disabled.completed .step-marker {
+  background-color: #1EB475;
+  border: 2px solid #1EB475;
+  color: white;
+}
+.wizard .wizard-body .wizard-nav .nav-pills > li.active > a,
+.wizard .wizard-body .wizard-nav .nav-pills > li.active > a:focus,
+.wizard .wizard-body .wizard-nav .nav-pills > li.active > a:hover,
+.wizard .wizard-body .wizard-nav .nav > li > a:focus,
+.wizard .wizard-body .wizard-nav .nav > li > a:hover {
+  background-color: inherit;
+}
+.wizard .wizard-body .wizard-footer {
+  background: white;
+  padding: 15px 20px;
+}
+.wizard .wizard-body .wizard-footer button {
+  margin: 0 10px;
+}
+.checkbox-disabled-style {
+  background-color: #b2b8c1;
+  border-color: #b2b8c1;
+}
+input[type="checkbox"]:not(:checked),
+input[type="radio"]:not(:checked),
+input[type="checkbox"]:checked,
+input[type="radio"]:checked {
+  display: none;
+}
+input[type="checkbox"]:not(:checked) + label,
+input[type="radio"]:not(:checked) + label,
+input[type="checkbox"]:checked + label,
+input[type="radio"]:checked + label {
+  position: relative;
+  padding-left: 20px;
+}
+input[type="checkbox"]:not(:checked) + label:hover:before,
+input[type="radio"]:not(:checked) + label:hover:before,
+input[type="checkbox"]:checked + label:hover:before,
+input[type="radio"]:checked + label:hover:before {
+  border-color: #1491C1;
+  background-color: #1491C1;
+}
+input[type="checkbox"]:checked + label:before,
+input[type="radio"]:checked + label:before {
+  background-color: #1491C1;
+  border-color: #1491C1;
+}
+input[type="checkbox"][disabled] + label:before,
+input[type="radio"][disabled] + label:before,
+input[type="checkbox"].disabled + label:before,
+input[type="radio"].disabled + label:before,
+input[type="checkbox"][disabled] + label:hover:before,
+input[type="radio"][disabled] + label:hover:before,
+input[type="checkbox"].disabled + label:hover:before,
+input[type="radio"].disabled + label:hover:before {
+  background-color: #b2b8c1;
+  border-color: #b2b8c1;
+}
+input[type="checkbox"] + label:before {
+  content: '';
+  position: absolute;
+  left: 0;
+  top: 4px;
+  width: 10px;
+  height: 10px;
+  box-sizing: border-box;
+  border-radius: 2px;
+  border-width: 1px;
+  border-style: solid;
+  border-color: #ddd;
+}
+input[type="checkbox"]:checked + label:after {
+  content: '\2714';
+  color: #FFF;
+  position: absolute;
+  top: 0;
+  left: 2px;
+  font-size: 9px;
+}
+input[type="radio"] + label:before,
+input.radio + label:before {
+  content: '';
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 12px;
+  height: 12px;
+  box-sizing: border-box;
+  border-radius: 12px;
+  border-width: 1px;
+  border-style: solid;
+  border-color: #ddd;
+}
+input[type="radio"]:checked + label:after,
+input.radio:checked + label:after {
+  content: '';
+  background-color: #FFF;
+  position: absolute;
+  top: 3px;
+  left: 3px;
+  width: 6px;
+  height: 6px;
+  border-radius: 6px;
+}
+.navigation-bar-container {
+  height: auto;
+  width: 230px;
+  background-color: #323544;
+  padding: 0;
+  -ms-overflow-style: none;
+  transition: width 0.5s ease-out;
+  -webkit-font-smoothing: antialiased;
+}
+.navigation-bar-container ul.nav.side-nav-header {
+  width: 230px;
+  transition: width 0.5s ease-out;
+}
+.navigation-bar-container ul.nav.side-nav-header li.navigation-header {
+  background: #313d54;
+  padding: 15px 5px 15px 25px;
+  height: 55px;
+}
+.navigation-bar-container ul.nav.side-nav-header li.navigation-header > a.ambari-logo {
+  padding: 0;
+}
+.navigation-bar-container ul.nav.side-nav-header li.navigation-header > a.ambari-logo > img {
+  height: 25px;
+  float: left;
+  margin-left: -3px;
+}
+.navigation-bar-container ul.nav.side-nav-header li.navigation-header .btn-group {
+  cursor: pointer;
+  margin-top: 3px;
+}
+.navigation-bar-container ul.nav.side-nav-header li.navigation-header .btn-group:hover span.ambari-header,
+.navigation-bar-container ul.nav.side-nav-header li.navigation-header .btn-group:hover span.toggle-icon {
+  color: #fff;
+}
+.navigation-bar-container ul.nav.side-nav-header li.navigation-header .btn-group span.ambari-header {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-size: 20px;
+  width: 55px;
+  display: inline;
+  color: #b8bec4;
+  padding: 0 8px 0 10px;
+}
+.navigation-bar-container ul.nav.side-nav-header li.navigation-header .btn-group span.toggle-icon {
+  margin-bottom: 5px;
+  font-size: 13px;
+  display: inline-block;
+  vertical-align: middle;
+  color: #b8bec4;
+}
+.navigation-bar-container ul.nav.side-nav-header li.navigation-header .btn-group.open .dropdown-toggle {
+  -webkit-box-shadow: none;
+  box-shadow: none;
+}
+.navigation-bar-container ul.nav.side-nav-header li.navigation-header ul.dropdown-menu {
+  top: 30px;
+}
+.navigation-bar-container ul.nav.side-nav-header li.navigation-header ul.dropdown-menu li > a {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-size: 14px;
+  color: #666;
+  line-height: 1.42;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+.navigation-bar-container ul.nav.side-nav-header li.navigation-header ul.dropdown-menu li > a:hover {
+  background: #f5f5f5;
+}
+.navigation-bar-container ul.nav.side-nav-menu,
+.navigation-bar-container ul.nav.side-nav-footer {
+  background-color: #323544;
+  width: 230px;
+  transition: width 0.5s ease-out;
+}
+.navigation-bar-container ul.nav.side-nav-menu li,
+.navigation-bar-container ul.nav.side-nav-footer li {
+  padding: 0;
+  margin: 0;
+}
+.navigation-bar-container ul.nav.side-nav-menu li.navigation-footer > a,
+.navigation-bar-container ul.nav.side-nav-footer li.navigation-footer > a,
+.navigation-bar-container ul.nav.side-nav-menu li.submenu-li > a,
+.navigation-bar-container ul.nav.side-nav-footer li.submenu-li > a,
+.navigation-bar-container ul.nav.side-nav-menu li.mainmenu-li > a,
+.navigation-bar-container ul.nav.side-nav-footer li.mainmenu-li > a {
+  display: table-cell;
+  vertical-align: middle;
+  width: 230px;
+  border-radius: 0;
+  -moz-border-radius: 0;
+  -webkit-border-radius: 0;
+  white-space: nowrap;
+}
+.navigation-bar-container ul.nav.side-nav-menu li.navigation-footer > a .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-footer li.navigation-footer > a .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-menu li.submenu-li > a .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-footer li.submenu-li > a .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-menu li.mainmenu-li > a .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-footer li.mainmenu-li > a .navigation-menu-item {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-size: 14px;
+  color: #b8bec4;
+  padding-left: 8px;
+}
+.navigation-bar-container ul.nav.side-nav-menu li.navigation-footer > a .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-footer li.navigation-footer > a .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-menu li.submenu-li > a .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-footer li.submenu-li > a .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-menu li.mainmenu-li > a .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-footer li.mainmenu-li > a .navigation-icon {
+  line-height: 18px;
+  font-size: 18px;
+  color: #b8bec4;
+}
+.navigation-bar-container ul.nav.side-nav-menu li.navigation-footer > a .toggle-icon,
+.navigation-bar-container ul.nav.side-nav-footer li.navigation-footer > a .toggle-icon,
+.navigation-bar-container ul.nav.side-nav-menu li.submenu-li > a .toggle-icon,
+.navigation-bar-container ul.nav.side-nav-footer li.submenu-li > a .toggle-icon,
+.navigation-bar-container ul.nav.side-nav-menu li.mainmenu-li > a .toggle-icon,
+.navigation-bar-container ul.nav.side-nav-footer li.mainmenu-li > a .toggle-icon {
+  line-height: 14px;
+  font-size: 14px;
+  color: #b8bec4;
+  padding: 3px 5px 3px 10px;
+}
+.navigation-bar-container ul.nav.side-nav-menu li.navigation-footer > a,
+.navigation-bar-container ul.nav.side-nav-footer li.navigation-footer > a,
+.navigation-bar-container ul.nav.side-nav-menu li.mainmenu-li > a,
+.navigation-bar-container ul.nav.side-nav-footer li.mainmenu-li > a {
+  padding: 10px 5px 10px 20px;
+}
+.navigation-bar-container ul.nav.side-nav-menu li.submenu-li > a,
+.navigation-bar-container ul.nav.side-nav-footer li.submenu-li > a {
+  padding: 10px 5px 10px 25px;
+}
+.navigation-bar-container ul.nav.side-nav-menu li.navigation-footer,
+.navigation-bar-container ul.nav.side-nav-footer li.navigation-footer {
+  background: #313d54;
+  height: 50px;
+}
+.navigation-bar-container ul.nav.side-nav-menu li.navigation-footer a .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-footer li.navigation-footer a .navigation-icon {
+  color: #31823a;
+  font-size: 20px;
+  position: relative;
+  padding: 0 15px;
+  left: calc(30%);
+}
+.navigation-bar-container ul.nav.side-nav-menu li.navigation-footer a .navigation-icon:hover,
+.navigation-bar-container ul.nav.side-nav-footer li.navigation-footer a .navigation-icon:hover {
+  color: #fff;
+}
+.navigation-bar-container ul.nav.side-nav-menu li > ul > li,
+.navigation-bar-container ul.nav.side-nav-footer li > ul > li {
+  background-color: #323544;
+}
+.navigation-bar-container ul.nav.side-nav-menu li > ul > li a,
+.navigation-bar-container ul.nav.side-nav-footer li > ul > li a {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-size: 14px;
+  color: #999;
+}
+.navigation-bar-container ul.nav.side-nav-menu li > ul > li a .submenu-icon,
+.navigation-bar-container ul.nav.side-nav-footer li > ul > li a .submenu-icon {
+  line-height: 14px;
+  font-size: 14px;
+}
+.navigation-bar-container ul.nav.side-nav-menu li > ul > li > a:hover,
+.navigation-bar-container ul.nav.side-nav-footer li > ul > li > a:hover,
+.navigation-bar-container ul.nav.side-nav-menu li > a:hover,
+.navigation-bar-container ul.nav.side-nav-footer li > a:hover {
+  background: #404351;
+  cursor: pointer;
+  color: #fff;
+}
+.navigation-bar-container ul.nav.side-nav-menu li > ul > li > a:hover .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-footer li > ul > li > a:hover .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-menu li > a:hover .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-footer li > a:hover .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-menu li > ul > li > a:hover .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-footer li > ul > li > a:hover .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-menu li > a:hover .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-footer li > a:hover .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-menu li > ul > li > a:hover .toggle-icon,
+.navigation-bar-container ul.nav.side-nav-footer li > ul > li > a:hover .toggle-icon,
+.navigation-bar-container ul.nav.side-nav-menu li > a:hover .toggle-icon,
+.navigation-bar-container ul.nav.side-nav-footer li > a:hover .toggle-icon,
+.navigation-bar-container ul.nav.side-nav-menu li > ul > li > a:hover .submenu-item,
+.navigation-bar-container ul.nav.side-nav-footer li > ul > li > a:hover .submenu-item,
+.navigation-bar-container ul.nav.side-nav-menu li > a:hover .submenu-item,
+.navigation-bar-container ul.nav.side-nav-footer li > a:hover .submenu-item {
+  color: #fff;
+}
+.navigation-bar-container ul.nav.side-nav-menu li.active:not(.has-sub-menu),
+.navigation-bar-container ul.nav.side-nav-footer li.active:not(.has-sub-menu),
+.navigation-bar-container ul.nav.side-nav-menu li.active.collapsed,
+.navigation-bar-container ul.nav.side-nav-footer li.active.collapsed {
+  background: #404351;
+  cursor: pointer;
+}
+.navigation-bar-container ul.nav.side-nav-menu li.active:not(.has-sub-menu) > a,
+.navigation-bar-container ul.nav.side-nav-footer li.active:not(.has-sub-menu) > a,
+.navigation-bar-container ul.nav.side-nav-menu li.active.collapsed > a,
+.navigation-bar-container ul.nav.side-nav-footer li.active.collapsed > a {
+  color: #fff;
+}
+.navigation-bar-container ul.nav.side-nav-menu li.active:not(.has-sub-menu) > a .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-footer li.active:not(.has-sub-menu) > a .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-menu li.active.collapsed > a .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-footer li.active.collapsed > a .navigation-menu-item,
+.navigation-bar-container ul.nav.side-nav-menu li.active:not(.has-sub-menu) > a .submenu-item,
+.navigation-bar-container ul.nav.side-nav-footer li.active:not(.has-sub-menu) > a .submenu-item,
+.navigation-bar-container ul.nav.side-nav-menu li.active.collapsed > a .submenu-item,
+.navigation-bar-container ul.nav.side-nav-footer li.active.collapsed > a .submenu-item,
+.navigation-bar-container ul.nav.side-nav-menu li.active:not(.has-sub-menu) > a .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-footer li.active:not(.has-sub-menu) > a .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-menu li.active.collapsed > a .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-footer li.active.collapsed > a .navigation-icon,
+.navigation-bar-container ul.nav.side-nav-menu li.active:not(.has-sub-menu) > a .toggle-icon,
+.navigation-bar-container ul.nav.side-nav-footer li.active:not(.has-sub-menu) > a .toggle-icon,
+.navigation-bar-container ul.nav.side-nav-menu li.active.collapsed > a .toggle-icon,
+.navigation-bar-container ul.nav.side-nav-footer li.active.collapsed > a .toggle-icon {
+  color: #fff;
+}
+.navigation-bar-container ul.nav.side-nav-menu li.active:not(.has-sub-menu) > a:after,
+.navigation-bar-container ul.nav.side-nav-footer li.active:not(.has-sub-menu) > a:after,
+.navigation-bar-container ul.nav.side-nav-menu li.active.collapsed > a:after,
+.navigation-bar-container ul.nav.side-nav-footer li.active.collapsed > a:after {
+  left: 0;
+  top: 50%;
+  border: solid transparent;
+  border-width: 10px 7px;
+  content: " ";
+  height: 0;
+  width: 0;
+  position: absolute;
+  pointer-events: none;
+  border-color: transparent;
+  border-left-color: #31823a;
+  margin-top: -12px;
+}
+.navigation-bar-container ul.nav.side-nav-menu .more-actions,
+.navigation-bar-container ul.nav.side-nav-footer .more-actions {
+  display: none;
+  position: absolute;
+  top: 14px;
+  right: 33px;
+  line-height: 25px;
+  width: 20px;
+  text-align: center;
+  font-size: 14px;
+  cursor: pointer;
+  vertical-align: middle;
+  color: #fff;
+}
+.navigation-bar-container ul.nav.side-nav-menu .more-actions .dropdown-menu > li > a,
+.navigation-bar-container ul.nav.side-nav-footer .more-actions .dropdown-menu > li > a {
+  color: #666;
+}
+.navigation-bar-container ul.nav.side-nav-menu .more-actions .dropdown-menu > li > a i,
+.navigation-bar-container ul.nav.side-nav-footer .more-actions .dropdown-menu > li > a i {
+  color: #666;
+}
+.navigation-bar-container ul.nav.side-nav-menu .more-actions .dropdown-menu > li > a:hover,
+.navigation-bar-container ul.nav.side-nav-footer .more-actions .dropdown-menu > li > a:hover {
+  background: #f5f5f5;
+}
+.navigation-bar-container ul.nav.side-nav-menu .menu-item-name,
+.navigation-bar-container ul.nav.side-nav-footer .menu-item-name {
+  display: inline-block;
+  vertical-align: bottom;
+  max-width: 100px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  -o-text-overflow: ellipsis;
+  -ms-text-overflow: ellipsis;
+  white-space: nowrap;
+}
+.navigation-bar-container .nav-pills > li.active > a,
+.navigation-bar-container .nav-pills > li.active > a:focus,
+.navigation-bar-container .nav-pills > li.active > a:hover,
+.navigation-bar-container .nav > li > a:focus,
+.navigation-bar-container .nav > li > a:hover {
+  background-color: inherit;
+}
+.navigation-bar-container.collapsed {
+  width: 50px;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-header {
+  width: 50px;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-header li.navigation-header {
+  padding: 15px 0 15px 15px;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-header li.navigation-header span.ambari-header,
+.navigation-bar-container.collapsed ul.nav.side-nav-header li.navigation-header span.toggle-icon,
+.navigation-bar-container.collapsed ul.nav.side-nav-header li.navigation-header .dropdown-menu {
+  display: none;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-menu,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer {
+  width: 50px;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li a,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li a {
+  padding: 15px 0 15px 15px;
+  width: 50px;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li a .navigation-menu-item,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li a .navigation-menu-item,
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li a .toggle-icon,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li a .toggle-icon {
+  display: none;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li.navigation-footer a .navigation-icon,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li.navigation-footer a .navigation-icon {
+  padding: 0 5px;
+  left: 0;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li ul.sub-menu,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li ul.sub-menu {
+  display: none;
+  width: 230px;
+  position: absolute;
+  z-index: 100;
+  top: 0;
+  left: 50px;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li.submenu-li > a,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li.submenu-li > a {
+  padding: 10px 5px 10px 25px;
+  width: 230px;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li.active,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li.active {
+  background: #404351;
+  cursor: pointer;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li.active > a,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li.active > a {
+  color: #fff;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li.active > a .navigation-menu-item,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li.active > a .navigation-menu-item,
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li.active > a .submenu-item,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li.active > a .submenu-item,
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li.active > a .navigation-icon,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li.active > a .navigation-icon,
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li.active > a .toggle-icon,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li.active > a .toggle-icon {
+  color: #fff;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-menu li.active > a:after,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer li.active > a:after {
+  left: 0;
+  top: 50%;
+  border: solid transparent;
+  border-width: 12px 6px;
+  content: " ";
+  height: 0;
+  width: 0;
+  position: absolute;
+  pointer-events: none;
+  border-color: transparent;
+  border-left-color: #31823a;
+  margin-top: -12px;
+}
+.navigation-bar-container.collapsed ul.nav.side-nav-menu .more-actions,
+.navigation-bar-container.collapsed ul.nav.side-nav-footer .more-actions {
+  display: none;
+}
+.navigation-bar-fit-height {
+  position: fixed;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 2079;
+}
+.navigation-bar-fit-height .side-nav-header {
+  position: absolute;
+  top: 0;
+}
+.navigation-bar-fit-height .side-nav-menu {
+  position: absolute;
+  top: 55px;
+  bottom: 50px;
+}
+.navigation-bar-fit-height .side-nav-footer {
+  position: absolute;
+  bottom: 0;
+}
+.navigation-bar-fit-height .more-actions .dropdown-menu {
+  position: fixed;
+  top: auto;
+  left: auto;
+}
+.navigation-bar-fit-height .navigation-bar-container {
+  height: 100%;
+}
+.navigation-bar-fit-height .navigation-bar-container .side-nav-menu {
+  overflow-y: auto;
+}
+.notifications-group {
+  position: relative;
+  top: 1px;
+}
+#notifications-dropdown.dropdown-menu {
+  min-width: 300px;
+  max-width: 300px;
+  min-height: 150px;
+  padding: 0px;
+  z-index: 1000;
+  right: -50px;
+  left: auto;
+  top: 260%;
+  border: none;
+  -webkit-box-shadow: 0px 2px 10px 2px rgba(0, 0, 0, 0.29);
+  -moz-box-shadow: 0px 2px 10px 2px rgba(0, 0, 0, 0.29);
+  box-shadow: 0px 2px 10px 2px rgba(0, 0, 0, 0.29);
+}
+#notifications-dropdown.dropdown-menu .popup-arrow-up {
+  position: absolute;
+  right: 37px;
+  top: -40px;
+  width: 40px;
+  height: 40px;
+  overflow: hidden;
+}
+#notifications-dropdown.dropdown-menu .popup-arrow-up:after {
+  content: "";
+  position: absolute;
+  width: 20px;
+  height: 20px;
+  background: #fff;
+  transform: rotate(45deg);
+  top: 30px;
+  left: 10px;
+  box-shadow: -1px -1px 10px -2px rgba(0, 0, 0, 0.5);
+}
+#notifications-dropdown.dropdown-menu .notifications-header {
+  border-bottom: 1px solid #eee;
+  padding: 15px 20px;
+}
+#notifications-dropdown.dropdown-menu .notifications-header .notifications-title {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-size: 16px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body {
+  padding: 0px 15px;
+  overflow: auto;
+  max-height: 500px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .no-alert-text {
+  padding: 15px 5px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table-controls {
+  padding: 10px 0px;
+  margin: 0px;
+  border-bottom: 1px solid #eee;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table-controls .state-filter {
+  padding: 0px;
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-size: 12px;
+  color: #666;
+  position: relative;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table-controls .state-filter .form-control.filter-select {
+  font-size: 12px;
+  color: #666;
+  height: 25px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table {
+  margin-top: 0px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody tr {
+  cursor: pointer;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody tr.no-alert-tr:hover {
+  cursor: default;
+  border-color: transparent;
+  border-bottom-color: #eee;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody tr.no-alert-tr:hover > td {
+  border-color: transparent;
+  background-color: white;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.status {
+  width: 9%;
+  padding: 15px 3px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.status .alert-state-CRITICAL {
+  color: #EF6162;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.status .alert-state-WARNING {
+  color: #E98A40;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.content {
+  width: 90%;
+  padding: 15px 3px 10px 3px;
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  line-height: 1.3;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.content .name {
+  font-weight: bold;
+  font-size: 14px;
+  color: #333;
+  margin-bottom: 5px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.content .description {
+  font-size: 12px;
+  color: #666;
+  margin-bottom: 4px;
+  display: block;
+  display: -webkit-box;
+  -webkit-line-clamp: 3;
+  max-height: 47px;
+  /* For firefox */
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  /* Break long urls*/
+  overflow-wrap: break-word;
+  word-wrap: break-word;
+  -ms-word-break: break-all;
+  word-break: break-all;
+  word-break: break-word;
+  /* Adds a hyphen where the word breaks*/
+  -ms-hyphens: auto;
+  -moz-hyphens: auto;
+  -webkit-hyphens: auto;
+  hyphens: auto;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.content .timestamp {
+  text-align: right;
+  font-size: 11px;
+  color: #999;
+}
+#notifications-dropdown.dropdown-menu .notifications-footer {
+  border-top: 1px solid #eee;
+  padding: 15px;
+}
+.modal-backdrop {
+  background-color: #808080;
+}
+.modal .modal-content {
+  border-radius: 2px;
+}
+.modal .modal-content .modal-header,
+.modal .modal-content .modal-body,
+.modal .modal-content .modal-footer {
+  padding-left: 20px;
+  padding-right: 20px;
+}
+.modal .modal-content .modal-header {
+  border-bottom: none;
+  padding-top: 20px;
+  color: #666;
+  font-size: 20px;
+}
+.modal .modal-content .modal-header h4 {
+  margin: 0;
+  color: inherit;
+  font-size: inherit;
+}
+.modal .modal-content .modal-body {
+  color: #666;
+  font-size: 12px;
+}
+.modal .modal-content .modal-footer {
+  border-top: none;
+  padding-bottom: 20px;
+}
+.modal .modal-content .modal-footer .btn ~ .btn {
+  margin-left: 10px;
+}
+.accordion .panel-group,
+.wizard .wizard-body .wizard-content .accordion .panel-group {
+  margin-bottom: 0px;
+}
+.accordion .panel-group .panel,
+.wizard .wizard-body .wizard-content .accordion .panel-group .panel {
+  border-radius: 0px;
+  border: none;
+  margin-top: 0px;
+}
+.accordion .panel-group .panel .panel-heading,
+.wizard .wizard-body .wizard-content .accordion .panel-group .panel .panel-heading {
+  height: 50px;
+  padding: 15px 10px;
+  border: 1px solid;
+  border-color: #ddd transparent;
+  border-top: none;
+  background: #fff;
+}
+.accordion .panel-group .panel .panel-heading .panel-title,
+.wizard .wizard-body .wizard-content .accordion .panel-group .panel .panel-heading .panel-title {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+}
+.accordion .panel-group .panel .panel-heading .panel-title > a,
+.wizard .wizard-body .wizard-content .accordion .panel-group .panel .panel-heading .panel-title > a {
+  font-size: 18px;
+  color: #333;
+}
+.accordion .panel-group .panel .panel-heading .panel-title > i,
+.wizard .wizard-body .wizard-content .accordion .panel-group .panel .panel-heading .panel-title > i {
+  font-size: 20px;
+  color: #1491c1;
+}
+.accordion .panel-group .panel .panel-heading:hover,
+.wizard .wizard-body .wizard-content .accordion .panel-group .panel .panel-heading:hover {
+  background: #f3faff;
+  cursor: pointer;
+}
+.accordion .panel-group .panel .panel-body,
+.wizard .wizard-body .wizard-content .accordion .panel-group .panel .panel-body {
+  padding: 15px 10px 20px 20px;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+  font-family: 'Roboto', sans-serif;
+}
+h1,
+.h1 {
+  font-size: 24px;
+}
+h2,
+.h2 {
+  font-size: 18px;
+}
+body,
+.body {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-size: 14px;
+}
+.description {
+  font-family: 'Roboto', sans-serif;
+  font-size: 12px;
+  color: #000;
+}
+a,
+a:visited,
+a:focus {
+  color: #1491C1;
+  text-decoration: none;
+}
+a:hover,
+a:visited:hover,
+a:focus:hover {
+  text-decoration: underline;
+}
+a:active,
+a:visited:active,
+a:focus:active {
+  text-decoration: none;
+}
+a[disabled],
+a:visited[disabled],
+a:focus[disabled],
+a.disabled,
+a:visited.disabled,
+a:focus.disabled {
+  cursor: not-allowed;
+  color: #666;
+  text-decoration: none;
+}
+a[disabled]:hover,
+a:visited[disabled]:hover,
+a:focus[disabled]:hover,
+a.disabled:hover,
+a:visited.disabled:hover,
+a:focus.disabled:hover {
+  text-decoration: none;
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/bootstrap-hadoop.min.css b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/bootstrap-hadoop.min.css
new file mode 100644
index 0000000..ea438a9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/bootstrap-hadoop.min.css
@@ -0,0 +1,18 @@
+/**
+ * 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.
+ */
+@font-face{font-family:Roboto;font-weight:400;font-style:normal;src:url(fonts/Roboto-Regular-webfont.eot);src:url(fonts/Roboto-Regular-webfont.eot?#iefix) format('embedded-opentype'),url(fonts/Roboto-Regular-webfont.woff) format('woff'),url(fonts/Roboto-Regular-webfont.ttf) format('truetype'),url(fonts/Roboto-Regular-webfont.svg#robotoregular) format('svg')}.font-mixin{font-family:Roboto,sans-serif;font-weight:400;font-style:normal;line-height:1;color:#333}.btn,.btn:focus{outline:0;font- [...]
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/img/feather.png b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/img/feather.png
new file mode 100644
index 0000000..d4aff8b
Binary files /dev/null and b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/img/feather.png differ
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/img/jenkins.png b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/img/jenkins.png
new file mode 100644
index 0000000..7b332ec
Binary files /dev/null and b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/img/jenkins.png differ
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/img/loading.svg b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/img/loading.svg
new file mode 100644
index 0000000..fcdb87d
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/img/loading.svg
@@ -0,0 +1,8 @@
+<svg width="200px"  height="200px"  xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="lds-dual-ring" style="background: none;">
+    <circle cx="50" cy="50" ng-attr-r="{{config.radius}}" ng-attr-stroke-width="{{config.width}}" ng-attr-stroke="{{config.c1}}" ng-attr-stroke-dasharray="{{config.dasharray}}" fill="none" stroke-linecap="round" r="40" stroke-width="4" stroke="#84de5c" stroke-dasharray="62.83185307179586 62.83185307179586" transform="rotate(318 50 50)">
+      <animateTransform attributeName="transform" type="rotate" calcMode="linear" values="0 50 50;360 50 50" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite"></animateTransform>
+    </circle>
+    <circle cx="50" cy="50" ng-attr-r="{{config.radius2}}" ng-attr-stroke-width="{{config.width}}" ng-attr-stroke="{{config.c2}}" ng-attr-stroke-dasharray="{{config.dasharray2}}" ng-attr-stroke-dashoffset="{{config.dashoffset2}}" fill="none" stroke-linecap="round" r="35" stroke-width="4" stroke="#21d129" stroke-dasharray="54.97787143782138 54.97787143782138" stroke-dashoffset="54.97787143782138" transform="rotate(-318 50 50)">
+      <animateTransform attributeName="transform" type="rotate" calcMode="linear" values="0 50 50;-360 50 50" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite"></animateTransform>
+    </circle>
+  </svg>
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/img/pattern-f61c2e99f82389a67432f54155c5f483.png b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/img/pattern-f61c2e99f82389a67432f54155c5f483.png
new file mode 100644
index 0000000..2d62a14
Binary files /dev/null and b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/img/pattern-f61c2e99f82389a67432f54155c5f483.png differ
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/specific.css b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/specific.css
new file mode 100644
index 0000000..3e75f91
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/specific.css
@@ -0,0 +1,252 @@
+/**
+ * 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.
+ */
+
+.tile {
+  margin: 5px 5px 0px 5px;
+  padding: 5px;
+  border: 1px solid #cdcdcd;
+  height: 210px;
+  overflow: hidden;
+  background-color: #ffffff;
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+  min-width: 250px;
+}
+
+.panel {
+  margin: 5px 0px 0px 0px;
+  padding: 5px;
+  border: 1px solid #cdcdcd;
+}
+
+.desc {
+  position: relative;
+  top: 100px;
+  margin: 5px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  height: 60px;
+  padding-right: 25px;
+}
+
+.appBanner {
+  display: block;
+  height: 40px;
+}
+
+.appList {
+  display: block;
+}
+
+html, body, .container {
+  height: 100%;
+}
+
+.container {
+    display:table;
+    width: 100%;
+    margin: 0;
+    padding: 0; /*set left/right padding according to needs*/
+    box-sizing: border-box;
+}
+
+.row {
+    height: 100%;
+    display: table-row;
+}
+
+.wizard {
+    height: 100%;
+    border: none;
+}
+
+.wizard-body {
+    height: 100%;
+}
+
+.navigation-header div.btn-group div {
+    display: inline;
+}
+
+.navigation-header div.btn-group div a:hover {
+    text-decoration: none;
+}
+
+.navigation-bar-container ul.nav.side-nav-menu li.mainmenu-li {
+    color: #999;
+}
+
+.navigation-bar-container ul.nav.side-nav-menu li.mainmenu-li:hover {
+    background-color: #404351;
+}
+
+.navigation-menu-item {
+    padding-left: 30px;
+}
+
+ul.nav.side-nav-menu li {
+    height: 55px;
+}
+
+.navigation-bar-container ul.nav.side-nav-menu li.mainmenu-li>a {
+    color: #b8bec4;
+}
+
+.navigation-bar {
+    height: 100%;
+}
+
+.navigation-bar-container {
+    height: 100%;
+}
+
+.content {
+    margin: 5px;
+}
+
+.mdl-shadow-4dp {
+    box-shadow: 0 4px 5px 0 rgba(0,0,0,.14), 0 1px 10px 0 rgba(0,0,0,.12), 0 2px 4px -1px rgba(0,0,0,.2);
+}
+
+/*
+ * hexagon
+ */
+.hexa, .hexa div {
+  position: absolute;
+  top: -5px;
+  left: 0px;
+  overflow: hidden;
+  width: 128px;
+  height: 128px;
+}
+.hexa {
+  width: 128px;
+  height: 96px;
+}
+.hexa div {
+  width: 100%;
+  height: 100%;
+}
+.hexa {
+      -webkit-transform: rotate(120deg);
+       -moz-transform: rotate(120deg);
+        -ms-transform: rotate(120deg);
+         -o-transform: rotate(120deg);
+            transform: rotate(120deg);
+}
+.hex1 {
+      -webkit-transform: rotate(-60deg);
+       -moz-transform: rotate(-60deg);
+        -ms-transform: rotate(-60deg);
+         -o-transform: rotate(-60deg);
+            transform: rotate(-60deg);
+}
+.hex2 {
+  box-shadow: 0 4px 5px 0 rgba(0,0,0,.14), 0 1px 10px 0 rgba(0,0,0,.12), 0 2px 4px -1px rgba(0,0,0,.2);
+      -webkit-transform: rotate(-60deg);
+       -moz-transform: rotate(-60deg);
+        -ms-transform: rotate(-60deg);
+         -o-transform: rotate(-60deg);
+            transform: rotate(-60deg);
+}
+
+/*
+ * card title
+ */
+.card-title {
+  position: absolute;
+  top: 5px;
+  left: 128px;
+}
+
+.card-desc {
+  margin: 10px;
+  padding-right: 25px;
+}
+
+.card-footer {
+  position: relative;
+  margin: 0px 5px 5px 5px;
+  padding: 5px;
+  background-color: #eeeeee;
+  line-height: 25px;
+  height: 45px;
+  color: #666;
+  font-family: Roboto,sans-serif!important;
+  font-size: 14;
+  min-width: 250px;
+  border-bottom-left-radius: 4px;
+  border-bottom-right-radius: 4px;
+}
+
+.toparea {
+  position: fixed;
+  top: 0px;
+  left: 230px;
+  width: calc(100% - 230px);
+  height: 300px;
+  color: #2c2e3b;
+  background: -webkit-linear-gradient(left,#2e3b51 ,#181d2b);
+  background: -moz-linear-gradient(right,#2e3b51,#181d2b);
+  background: -o-linear-gradient(right,#2e3b51,#181d2b);
+  background: linear-gradient(to right,#2e3b51 ,#181d2b);
+}
+
+.pattern-wrapper {
+  width: 100%;
+  height: 300px;
+  background-image: url(img/pattern-f61c2e99f82389a67432f54155c5f483.png);
+  background-repeat: no-repeat;
+  background-position: 0px 30px;
+  position: absolute;
+  top: 0;
+  left: 0;
+}
+
+.recommended {
+  color: #fff;
+}
+
+.loader-wrapper {
+  position: fixed;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  background: #222222;
+  z-index: 1000;
+  opacity: 0.3;
+}
+
+.loader {
+  display: table;
+  margin: 0 auto;
+  position: relative;
+  top: 50%;
+  transform: translateY(-50%);
+}
+
+.loader img {
+  width: 300px;
+  height: 225px;
+}
+
+.infobox {
+    font-size:14px;
+    margin:20px;
+    padding:10px;
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/theme.css b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/theme.css
new file mode 100644
index 0000000..e787efe
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/css/theme.css
@@ -0,0 +1,30 @@
+/**
+ * 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.
+ */
+.theme-dropdown .dropdown-menu {
+    position: static;
+    display: block;
+    margin-bottom: 20px;
+}
+
+.theme-showcase > p > .btn {
+    margin: 5px 0;
+}
+
+.theme-showcase .navbar .container {
+    width: auto;
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/index.html b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/index.html
new file mode 100644
index 0000000..2a96027
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/index.html
@@ -0,0 +1,82 @@
+<!---
+  Licensed 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. See accompanying LICENSE file.
+-->
+<!doctype html>
+<html lang="en" data-ng-app="app">
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>YARN Application Catalog</title>
+    <link rel="stylesheet" href="vendor/bootstrap/dist/css/bootstrap.min.css">
+    <link rel="stylesheet" href="vendor/bootstrap/dist/css/bootstrap-theme.min.css">
+    <link href="css/bootstrap-hadoop.css" rel="stylesheet">
+    <link rel="stylesheet" href="css/theme.css">
+    <link rel="stylesheet" href="css/specific.css">
+</head>
+<body role="document">
+<div ng-controller="LoadScreenController" class="loader-wrapper {{loadScreen}}">
+  <div class="loader"><img src="/css/img/loading.svg"></div>
+</div>
+<div class="container">
+  <div class="row">
+      <div class="navigation-bar-container col-sm-3 col-md-3 col-lg-3" ng-controller="AppListController">
+        <ul class="side-nav-header nav nav-pills nav-stacked">
+          <li class="navigation-header">
+            <div class="btn-group">
+              <div>
+                <a href="#"><span class="ambari-header">Applications</span></a>
+              </div>
+              <div class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                <span class="toggle-icon glyphicon glyphicon-menu-down"></span>
+              </div>
+              <ul class="dropdown-menu">
+                <li><a href="#!/">Appstore</a></li>
+                <li><a href="#!/new">Register App</a></li>
+              </ul>
+            </div>
+          </li>
+        </ul>
+        <ul class="side-nav-menu nav nav-pills nav-stacked">
+          <li class="mainmenu-li" ng-repeat="yarnApp in appList">
+            <a href="#!/app/{{yarnApp.id}}"><span class="glyphicon glyphicon-ok-sign"></span> {{yarnApp.name}}</a>
+            <a ng-click="deleteApp(yarnApp.id,yarnApp.name)" class="icon-width"><span class="glyphicon glyphicon-remove pull-right"></span></a>
+            <span class="navigation-menu-item">{{yarnApp.app}}</span>
+          </li>
+        </ul>
+        <ul class="side-nav-footer nav nav-pills nav-stacked">
+          <li class="navigation-footer">
+            <a href="#" data-toggle="collapse-side-nav">
+              <span class="navigation-icon fa fa-angle-double-left"></span>
+            </a>
+          </li>
+        </ul>
+      </div>
+
+    <div class="col-xs-9 col-md-9 col-lg-9">
+      <div data-ng-view></div>
+    </div>
+  </div>
+</div>
+<script src="vendor/jquery/dist/jquery.min.js"></script>
+<script src="vendor/bootstrap/dist/js/bootstrap.min.js"></script>
+<script src="vendor/angular/angular.min.js"></script>
+<script src="vendor/angular-route/angular-route.min.js"></script>
+<script src="js/bootstrap-hadoop.min.js"></script>
+<script src="js/app.js"></script>
+<script src="js/controllers.js"></script>
+<script src="js/filters.js"></script>
+<script src="js/routes.js"></script>
+<script src="js/services.js"></script>
+</body>
+</html>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/js/bootstrap-hadoop.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/js/bootstrap-hadoop.js
new file mode 100644
index 0000000..bd57d5c
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/js/bootstrap-hadoop.js
@@ -0,0 +1,284 @@
+/**
+ * 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.
+ */
+'use strict';
+
+$(document).ready(function () {
+  var $accordionToggler = $(this).find('[data-toggle="collapseAccordion"]');
+  $accordionToggler.off('click').on('click', function (event) {
+    var $this = $(this);
+    $this.siblings('.panel-body').slideToggle(500);
+    $this.children().children('.panel-toggle').toggleClass('fa-angle-down fa-angle-up');
+    event.stopPropagation();
+    return false;
+  });
+});
+'use strict';
+
+(function ($) {
+
+  /**
+   * jQuery plugin for navigation bars
+   * Usage:
+   * <pre>
+   *   $('.navigation-bar').navigationBar();
+   * </pre>
+   *
+   * @param {object} options see <code>$.fn.navigationBar.defaults</code>
+   * @returns {$}
+   */
+
+  $.fn.navigationBar = function (options) {
+
+    var settings = $.extend({}, $.fn.navigationBar.defaults, options);
+
+    return this.each(function () {
+      var _this = this;
+
+      var containerSelector = '.navigation-bar-container';
+      var $navigationContainer = $(this).find(containerSelector);
+      var $sideNavToggler = $(this).find('[data-toggle=' + settings.navBarToggleDataAttr + ']');
+      var $subMenuToggler = $(this).find('[data-toggle=' + settings.subMenuNavToggleDataAttr + ']');
+      var firstLvlMenuItemsSelector = '.side-nav-menu>li';
+      var secondLvlMenuItemsSelector = '.side-nav-menu>li>ul>li';
+      var $moreActions = $(this).find('.more-actions');
+      var $dropdownMenu = $moreActions.children('.dropdown-menu');
+
+      $subMenuToggler.each(function (index, toggler) {
+        return $(toggler).parent().addClass('has-sub-menu');
+      });
+
+      if (settings.fitHeight) {
+        $(this).addClass('navigation-bar-fit-height');
+
+        // make scrolling effect on side nav ONLY, i.e. not effected on ambari main contents
+        $(this).find('.side-nav-menu').on('DOMMouseScroll mousewheel', function (ev) {
+          var $this = $(this),
+              scrollTop = this.scrollTop,
+              scrollHeight = this.scrollHeight,
+              height = $this.innerHeight(),
+              delta = ev.originalEvent.wheelDelta,
+              up = delta > 0;
+          var prevent = function prevent() {
+            ev.stopPropagation();
+            ev.preventDefault();
+            ev.returnValue = false;
+            return false;
+          };
+
+          if (!up && -delta > scrollHeight - height - scrollTop) {
+            // Scrolling down, but this will take us past the bottom.
+            $this.scrollTop(scrollHeight);
+            return prevent();
+          } else if (up && delta > scrollTop) {
+            // Scrolling up, but this will take us past the top.
+            $this.scrollTop(0);
+            return prevent();
+          }
+        });
+      }
+
+      //set main content left margin based on the width of side-nav
+      var containerWidth = $navigationContainer.width();
+      if (settings.moveLeftContent) {
+        $(settings.content).css('margin-left', containerWidth);
+      }
+      if (settings.moveLeftFooter) {
+        $(settings.footer).css('margin-left', containerWidth);
+      }
+
+      function popStateHandler() {
+        var path = window.location.pathname + window.location.hash;
+        $navigationContainer.find('li a').each(function (index, link) {
+          var $link = $(link);
+          var href = $link.attr('data-href') || $link.attr('href');
+          if (path.indexOf(href) !== -1 && ['', '#'].indexOf(href) === -1) {
+            $link.parent().addClass('active');
+          } else {
+            $link.parent().removeClass('active');
+          }
+        });
+      }
+
+      if (settings.handlePopState) {
+        popStateHandler();
+        $(window).bind('popstate', popStateHandler);
+      }
+
+      function clickHandler(el) {
+        var $li = $(el).parent();
+        var activeClass = settings.activeClass;
+
+        var activeMenuItems = firstLvlMenuItemsSelector + '.' + activeClass;
+        var activeSubMenuItems = secondLvlMenuItemsSelector + '.' + activeClass;
+        $navigationContainer.find(activeMenuItems).removeClass(activeClass);
+        $navigationContainer.find(activeSubMenuItems).removeClass(activeClass);
+        $li.addClass(activeClass);
+      }
+
+      /**
+       * Click on menu item
+       */
+      $(firstLvlMenuItemsSelector + '>a').on('click', function () {
+        clickHandler(this);
+      });
+
+      /**
+       * Click on sub menu item
+       */
+      $(secondLvlMenuItemsSelector + '>a').on('click', function () {
+        clickHandler(this);
+        $(this).parent().parent().parent().addClass(settings.activeClass);
+      });
+
+      /**
+       * Slider for sub menu
+       */
+      $subMenuToggler.off('click').on('click', function (event) {
+        // ignore click if navigation-bar is collapsed
+        if ($navigationContainer.hasClass('collapsed')) {
+          return false;
+        }
+        var $this = $(this);
+        $this.siblings('.sub-menu').slideToggle(600, function () {
+          var $topMenuItem = $this.parent();
+          var $subMenu = $topMenuItem.find('ul');
+          return $subMenu.is(':visible') ? $topMenuItem.removeClass('collapsed') : $topMenuItem.addClass('collapsed');
+        });
+        $this.children('.toggle-icon').toggleClass(settings.menuLeftClass + ' ' + settings.menuDownClass);
+        event.stopPropagation();
+        return false;
+      });
+
+      /**
+       * Hovering effects for "more actions icon": "..."
+       */
+      $(this).find('.mainmenu-li>a').hover(function () {
+        var $moreIcon = $(this).siblings('.more-actions');
+        if ($moreIcon.length && !$navigationContainer.hasClass('collapsed')) {
+          $moreIcon.css('display', 'inline-block');
+        }
+      }, function () {
+        var $moreIcon = $(this).siblings('.more-actions');
+        if ($moreIcon.length && !$navigationContainer.hasClass('collapsed')) {
+          $moreIcon.hide();
+        }
+      });
+      $moreActions.hover(function () {
+        $(this).css('display', 'inline-block');
+      });
+      if (settings.fitHeight) {
+        $moreActions.on('click', function () {
+          // set actions submenu position
+          var $moreIcon = $(this);
+          var $header = $('.side-nav-header');
+          $dropdownMenu.css({
+            top: $moreIcon.offset().top - $header.offset().top + 20 + 'px',
+            left: $moreIcon.offset().left + 'px'
+          });
+        });
+      }
+      $dropdownMenu.on('click', function () {
+        // some action was triggered, should hide this icon
+        var moreIcon = $(this).parent();
+        setTimeout(function () {
+          moreIcon.hide();
+        }, 1000);
+      });
+      $navigationContainer.children('.side-nav-menu').scroll(function () {
+        $moreActions.removeClass('open');
+      });
+
+      /**
+       * Expand/collapse navigation bar
+       */
+      $sideNavToggler.click(function () {
+
+        $navigationContainer.toggleClass('collapsed').promise().done(function () {
+          var subMenuSelector = 'ul.sub-menu';
+          var $subMenus = $navigationContainer.find(subMenuSelector);
+          var $subMenuItems = $navigationContainer.find('.side-nav-menu>li');
+          if ($navigationContainer.hasClass('collapsed')) {
+            // set sub menu invisible when collapsed
+            $subMenus.hide();
+            $moreActions.hide();
+            // set the hover effect when collapsed, should show sub-menu on hovering
+            $subMenuItems.hover(function () {
+              $(this).find(subMenuSelector).show();
+              // set sub-menu position
+              var $parent = $(this);
+              var $header = $('.side-nav-header');
+              if (settings.fitHeight) {
+                $(this).find(subMenuSelector).css({
+                  position: 'fixed',
+                  top: $parent.offset().top - $header.offset().top + 'px',
+                  left: 50 + 'px'
+                });
+              }
+            }, function () {
+              $(this).find(subMenuSelector).hide();
+            });
+          } else {
+            // keep showing all sub menu
+            $subMenus.show().each(function (index, item) {
+              return $(item).parent().removeClass('collapsed');
+            });
+            $subMenuItems.unbind('mouseenter mouseleave');
+            $navigationContainer.find('.toggle-icon').removeClass(settings.menuLeftClass).addClass(settings.menuDownClass);
+            // set sub-menu position
+            if (settings.fitHeight) {
+              $(_this).find(subMenuSelector).css({
+                position: 'relative',
+                top: 0,
+                left: 0
+              });
+            }
+          }
+
+          $navigationContainer.on('transitionend', function () {
+            //set main content left margin based on the width of side-nav
+            var containerWidth = $navigationContainer.width();
+            if (settings.moveLeftContent) {
+              $(settings.content).css('margin-left', containerWidth);
+            }
+            if (settings.moveLeftFooter) {
+              $(settings.footer).css('margin-left', containerWidth);
+            }
+          });
+          $sideNavToggler.find('span').toggleClass(settings.collapseNavBarClass + ' ' + settings.expandNavBarClass);
+        });
+        return false;
+      });
+    });
+  };
+
+  $.fn.navigationBar.defaults = {
+    handlePopState: true,
+    fitHeight: false,
+    content: '#main',
+    footer: 'footer',
+    moveLeftContent: true,
+    moveLeftFooter: true,
+    menuLeftClass: 'glyphicon-menu-right',
+    menuDownClass: 'glyphicon-menu-down',
+    collapseNavBarClass: 'fa-angle-double-left',
+    expandNavBarClass: 'fa-angle-double-right',
+    activeClass: 'active',
+    navBarToggleDataAttr: 'collapse-side-nav',
+    subMenuNavToggleDataAttr: 'collapse-sub-menu'
+  };
+})(jQuery);
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/js/bootstrap-hadoop.min.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/js/bootstrap-hadoop.min.js
new file mode 100644
index 0000000..6872799
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/js/bootstrap-hadoop.min.js
@@ -0,0 +1,19 @@
+/**
+ * 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.
+ */
+"use strict";$(document).ready(function(){$(this).find('[data-toggle="collapseAccordion"]').off("click").on("click",function(n){var l=$(this);return l.siblings(".panel-body").slideToggle(500),l.children().children(".panel-toggle").toggleClass("fa-angle-down fa-angle-up"),n.stopPropagation(),!1})});
+"use strict";!function(e){e.fn.navigationBar=function(n){var t=e.extend({},e.fn.navigationBar.defaults,n);return this.each(function(){function n(){var n=window.location.pathname+window.location.hash;i.find("li a").each(function(t,a){var s=e(a),i=s.attr("data-href")||s.attr("href");-1!==n.indexOf(i)&&-1===["","#"].indexOf(i)?s.parent().addClass("active"):s.parent().removeClass("active")})}function a(n){var a=e(n).parent(),s=t.activeClass,o=r+"."+s,l=f+"."+s;i.find(o).removeClass(s),i.find [...]
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/partials/deploy.html b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/partials/deploy.html
new file mode 100644
index 0000000..534d0e9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/partials/deploy.html
@@ -0,0 +1,80 @@
+<!---
+  Licensed 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. See accompanying LICENSE file.
+-->
+<div class="container content">
+    <div class="row">
+      <div class="col-xs-12 col-md-12 col-lg-12">
+        <div class="form-group">
+          <h1>Deploy Application</h1>
+        </div>
+      </div>
+    </div>
+
+    <div class="row">
+      <div class="col-xs-2 col-md-2 col-lg-2">
+        <img ng-src="{{details.icon}}" alt="" width="128" height="128" ng-if="details.icon != null" />
+      </div>
+      <div class="col-xs-10 col-md-10 col-lg-10">
+        <div class="form-group">
+          <h2>{{details.org}}/{{details.name}}</h2>
+          {{details.desc}}
+        </div>
+      </div>
+    </div>
+
+    <div class="row">
+      <div class="col-xs-12 col-md-12 col-lg-12">
+        <div class="form-group">
+          <label>Application Name</label>
+          <input type=text name="name" class="form-control" ng-model="details.app.name" autofocus />
+        </div>
+        <div class="form-group">
+          <label>Queue</label>
+          <input type=text name="queue" class="form-control" ng-model="details.app.queue" />
+        </div>
+      </div>
+    </div>
+
+    <div class="row">
+      <div class="col-xs-12 col-md-12 col-lg-12" ng-repeat="docker in details.app.components track by $index">
+        <div class="panel">
+          <div class="form-group">
+            <label>Component {{docker.name}}</label>
+          </div>
+          <div class="form-group">
+            <label>Number of containers</label>
+            <input type=text name="artifact_id" class="form-control" ng-model="docker.number_of_containers" />
+          </div>
+          <div class="form-group">
+            <label>Environments</label>
+            <textarea json-text name="env" class="form-control" ng-model="docker.configuration.env"/></textarea>
+          </div>
+          <div class="form-group">
+            <label>Properties</label>
+            <textarea json-text name="properties" class="form-control" ng-model="docker.configuration.properties"/></textarea>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <br>
+    <div class="row">
+      <div class="col-xs-12 col-md-12 col-lg-12">
+        <p>
+        <a class="btn btn-secondary" ng-click="launchApp(details.app)">LAUNCH</a>
+        <a class="btn btn-secondary" href="/">CANCEL</a>
+        <span class="infobox bg-info" ng-if="message">{{message}}</span>
+        <span class="infobox bg-danger" ng-if="error">{{error}}</span>
+      </div>
+    </div>
+</div>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/partials/details.html b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/partials/details.html
new file mode 100644
index 0000000..69ef912
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/partials/details.html
@@ -0,0 +1,64 @@
+<!---
+  Licensed 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. See accompanying LICENSE file.
+-->
+<div class="container content">
+  <div class="row">
+    <div class="col-xs-12 col-md-12 col-lg-12">
+      <a ng-click="stopApp(appName)" class="btn btn-secondary"><span class="glyphicon glyphicon-stop"></span> Stop</a>
+      <a ng-click="restartApp(appName)" class="btn btn-secondary"><span class="glyphicon glyphicon-refresh"></span> Start</a>
+      <div style="display:inline-block;" ng-repeat="(key, value) in details.yarnfile.quicklinks">
+        <a href="{{value}}" class="btn btn-secondary" ng-hide="checkServiceLink()"><span class="glyphicon glyphicon-new-window"></span> {{key}}</a>
+      </div>
+      {{details.yarnfile.state}}
+    </div>
+  </div>
+
+  <div class="row">
+    <div class="col-xs-12 col-md-12 col-lg-12" ng-repeat="docker in details.yarnfile.components">
+      <div class="panel">
+        <h3>{{docker.name}}</h3>
+        <p>Artifact: {{docker.artifact.id}}</p>
+        <p>Number of containers: {{docker.number_of_containers}}</p>
+        <p>CPU: {{docker.resource.cpus}}</p>
+        <p>Memory: {{docker.resource.memory}}</p>
+        <p>Environments
+          <table class="table">
+            <tbody class="table-striped">
+              <tr ng-repeat="(key, value) in docker.configuration.env">
+                <td>{{key}}</td><td>{{value}}</td>
+              </tr>
+            </tbody>
+          </table>
+        </p>
+        <table class="table">
+          <thead>
+            <tr>
+              <th>Hostname</th>
+              <th>Container ID</th>
+              <th>Launch Time</th>
+              <th>State</th>
+            </tr>
+          </thead>
+          <tbody class="table-striped">
+            <tr ng-repeat="container in docker.containers">
+              <td>{{container.bare_host}}</td>
+              <td><a href="http://{{container.bare_host}}:8042/terminal/terminal.template?container={{container.id}}" target="_blank">{{container.id}}</a></td>
+              <td>{{container.launch_time | date:'yyyy-MM-dd HH:mm:ss Z'}}</td>
+              <td>{{container.state}}</td>
+            </tr>
+          </tbody>
+        </table>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/partials/home.html b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/partials/home.html
new file mode 100644
index 0000000..e2b7f08
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/partials/home.html
@@ -0,0 +1,52 @@
+<!---
+  Licensed 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. See accompanying LICENSE file.
+-->
+<div class="toparea"><div class="pattern-wrapper"></div></div>
+<div class="container content toparea pattern-wrapper">
+      <form>
+        <div class="input-group input-group-lg">
+          <div class="input-group-addon">
+            <span class="glyphicon glyphicon-search" id="search"></span>
+          </div>
+          <input type="text" class="form-control" placeholder="Search for applications from HDFS" aria-describedby="search" ng-model="searchText" ng-change="change(text)" />
+        </div>
+      </form>
+
+      <p></p>
+      <p class="recommended">Recommended</p>
+
+      <div ng-repeat="a in appStore" ng-if="$index % 3 == 0" class="row">
+        <div ng-repeat="i in [$index, $index + 1, $index + 2]"
+             ng-if="appStore[i] != null" class="col-xs-4 col-md-4 col-lg-4">
+          <div class="tile mdl-shadow-4dp">
+            <img ng-src="{{appStore[i].icon}}" alt="" width="128" height="128" ng-if="appStore[i] != null" />
+            <div class="card-title">
+              <h3>{{appStore[i].org}}</h3>
+              <h2>{{appStore[i].name}}</h2>
+            </div>
+            <div class="card-desc">
+              <p>{{appStore[i].desc}}</p>
+            </div>
+          </div>
+          <div class="card-footer mdl-shadow-4dp">
+            <div class="pull-left">
+              <!-- <span class="glyphicon glyphicon-thumbs-up"></span> {{appStore[i].like | counterValue}} -->
+              <span class="glyphicon glyphicon-cloud-download"></span> {{appStore[i].download | counterValue}}
+            </div>
+            <div class="pull-right">
+              <button class="btn btn-secondary" ng-click="deployApp(appStore[i].id)">DEPLOY</button>
+            </div>
+          </div>
+        </div>
+      </div>
+</div>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/partials/new.html b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/partials/new.html
new file mode 100644
index 0000000..4017225
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/partials/new.html
@@ -0,0 +1,111 @@
+<!---
+  Licensed 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. See accompanying LICENSE file.
+-->
+<div class="container content">
+    <div class="row">
+      <div class="col-xs-12 col-md-12 col-lg-12">
+        <div class="form-group">
+          <h1>Register Application</h1>
+        </div>
+        <div class="form-group">
+          <label>Organization Name</label>
+          <input type=text name="org" class="form-control" ng-model="details.organization" />
+        </div>
+        <div class="form-group">
+          <label>Application Name</label>
+          <input type=text name="name" class="form-control" ng-model="details.name" />
+        </div>
+        <div class="form-group">
+          <label>Version</label>
+          <input type=text name="version" class="form-control" ng-model="details.version" />
+        </div>
+        <div class="form-group">
+          <label>Description</label>
+          <textarea name="desc" class="form-control" ng-model="details.description"></textarea>
+        </div>
+        <div class="form-group">
+          <label>Quick Link</label>
+          <textarea json-text name="quicklink" class="form-control" ng-model="details.quicklinks"/></textarea>
+        </div>
+        <div class="form-group">
+          <label>Icon</label>
+          <input type=text name="icon" class="form-control" ng-model="details.icon" />
+        </div>
+      </div>
+    </div>
+
+    <div class="row">
+      <div class="col-xs-12 col-md-12 col-lg-12" ng-repeat="docker in details.components track by $index">
+        <div class="panel">
+          <div class="pull-right">
+            <a class="btn btn-secondary" ng-click="remove($index)">-</a>
+          </div>
+          <div class="form-group">
+            <label>Component Name</label>
+            <input type=text name="name" class="form-control" ng-model="docker.name" />
+          </div>
+          <div class="form-group">
+            <label>Artifact</label>
+            <input type=text name="artifact_id" class="form-control" ng-model="docker.artifact.id" />
+          </div>
+          <div class="form-group">
+            <label>Number of containers</label>
+            <input type=text name="artifact_id" class="form-control" ng-model="docker.number_of_containers" />
+          </div>
+          <div class="form-group">
+            <label>Launch Command</label>
+            <input type=text name="launch_command" class="form-control" ng-model="docker.launch_command" />
+          </div>
+          <div class="form-group">
+            <label>CPU</label>
+            <input type=text name="cpus" class="form-control" ng-model="docker.resource.cpus" />
+          </div>
+          <div class="form-group">
+            <label>Memory</label>
+            <input type=text name="memory" class="form-control" ng-model="docker.resource.memory" />
+          </div>
+          <div class="form-group">
+            <input type="checkbox" ng-attr-id="{{'checkbox-priv-' + $index}}" ng-model="docker.run_privileged_container">
+            <label for="checkbox-priv-{{$index}}"> Privileged Container</label>
+          </div>
+          <div class="form-group">
+            <label>Dependencies</label>
+            <input json-text type=text name="dependencies" class="form-control" ng-model="docker.dependencies" />
+          </div>
+          <div class="form-group">
+            <label>Placement Policy</label>
+            <input type=text name="placement" class="form-control" ng-model="docker.placement_policy.constraints" />
+          </div>
+          <div class="form-group">
+            <label>Environments</label>
+            <textarea json-text name="env" class="form-control" ng-model="docker.configuration.env"/></textarea>
+          </div>
+          <div class="form-group">
+            <label>Properties</label>
+            <textarea json-text name="properties" class="form-control" ng-model="docker.configuration.properties"/></textarea>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <br>
+    <div class="row">
+      <div class="col-xs-12 col-md-12 col-lg-12">
+        <p>
+        <a class="btn btn-secondary" ng-click="add()">+</a>
+        <a class="btn btn-secondary" ng-click="save()">Publish</a>
+        <span class="infobox bg-info" ng-if="message">{{message}}</span>
+        <span class="infobox bg-danger" ng-if="error">{{error}}</span>
+      </div>
+    </div>
+</div>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/theme.html b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/theme.html
new file mode 100644
index 0000000..a8a2a2d
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/main/webapp/theme.html
@@ -0,0 +1,649 @@
+<!---
+  Licensed 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. See accompanying LICENSE file.
+-->
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta name="description" content="">
+    <meta name="author" content="">
+
+    <title>Theme Template for Bootstrap</title>
+
+    <!-- Bootstrap core CSS -->
+    <link href="vendor/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
+    <!-- Bootstrap theme -->
+    <link href="vendor/bootstrap/dist/css/bootstrap-theme.min.css" rel="stylesheet">
+
+    <!-- Custom styles for this template -->
+    <link href="css/theme.css" rel="stylesheet">
+    <link href="css/bootstrap-hadoop.min.css" rel="stylesheet">
+
+</head>
+
+<body role="document">
+
+<!-- Fixed navbar -->
+<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
+    <div class="container">
+        <div class="navbar-header">
+            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+                <span class="sr-only">Toggle navigation</span>
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+            </button>
+            <a class="navbar-brand" href="#">Bootstrap theme</a>
+        </div>
+        <div class="navbar-collapse collapse">
+            <ul class="nav navbar-nav">
+                <li class="active"><a href="index.html">Home</a></li>
+                <li><a href="#about">About</a></li>
+                <li><a href="#contact">Contact</a></li>
+                <li class="dropdown">
+                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
+                    <ul class="dropdown-menu" role="menu">
+                        <li><a href="#">Action</a></li>
+                        <li><a href="#">Another action</a></li>
+                        <li><a href="#">Something else here</a></li>
+                        <li class="divider"></li>
+                        <li class="dropdown-header">Nav header</li>
+                        <li><a href="#">Separated link</a></li>
+                        <li><a href="#">One more separated link</a></li>
+                    </ul>
+                </li>
+            </ul>
+        </div>
+        <!--/.nav-collapse -->
+    </div>
+</div>
+
+<div class="container theme-showcase" role="main">
+
+<!-- Main jumbotron for a primary marketing message or call to action -->
+<div class="jumbotron">
+    <h1>Hello, world!</h1>
+
+    <p>This is a template for a simple marketing or informational website. It includes a large callout called a
+        jumbotron and three supporting pieces of content. Use it as a starting point to create something more
+        unique.</p>
+
+    <p><a href="#" class="btn btn-primary btn-lg" role="button">Learn more &raquo;</a></p>
+</div>
+
+
+<div class="page-header">
+    <h1>Buttons</h1>
+</div>
+<p>
+    <button type="button" class="btn btn-lg btn-default">Default</button>
+    <button type="button" class="btn btn-lg btn-primary">Primary</button>
+    <button type="button" class="btn btn-lg btn-success">Success</button>
+    <button type="button" class="btn btn-lg btn-info">Info</button>
+    <button type="button" class="btn btn-lg btn-warning">Warning</button>
+    <button type="button" class="btn btn-lg btn-danger">Danger</button>
+    <button type="button" class="btn btn-lg btn-link">Link</button>
+</p>
+<p>
+    <button type="button" class="btn btn-default">Default</button>
+    <button type="button" class="btn btn-primary">Primary</button>
+    <button type="button" class="btn btn-success">Success</button>
+    <button type="button" class="btn btn-info">Info</button>
+    <button type="button" class="btn btn-warning">Warning</button>
+    <button type="button" class="btn btn-danger">Danger</button>
+    <button type="button" class="btn btn-link">Link</button>
+</p>
+<p>
+    <button type="button" class="btn btn-sm btn-default">Default</button>
+    <button type="button" class="btn btn-sm btn-primary">Primary</button>
+    <button type="button" class="btn btn-sm btn-success">Success</button>
+    <button type="button" class="btn btn-sm btn-info">Info</button>
+    <button type="button" class="btn btn-sm btn-warning">Warning</button>
+    <button type="button" class="btn btn-sm btn-danger">Danger</button>
+    <button type="button" class="btn btn-sm btn-link">Link</button>
+</p>
+<p>
+    <button type="button" class="btn btn-xs btn-default">Default</button>
+    <button type="button" class="btn btn-xs btn-primary">Primary</button>
+    <button type="button" class="btn btn-xs btn-success">Success</button>
+    <button type="button" class="btn btn-xs btn-info">Info</button>
+    <button type="button" class="btn btn-xs btn-warning">Warning</button>
+    <button type="button" class="btn btn-xs btn-danger">Danger</button>
+    <button type="button" class="btn btn-xs btn-link">Link</button>
+</p>
+
+
+<div class="page-header">
+    <h1>Tables</h1>
+</div>
+<div class="row">
+    <div class="col-md-6">
+        <table class="table">
+            <thead>
+            <tr>
+                <th>#</th>
+                <th>First Name</th>
+                <th>Last Name</th>
+                <th>Username</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr>
+                <td>1</td>
+                <td>Mark</td>
+                <td>Otto</td>
+                <td>@mdo</td>
+            </tr>
+            <tr>
+                <td>2</td>
+                <td>Jacob</td>
+                <td>Thornton</td>
+                <td>@fat</td>
+            </tr>
+            <tr>
+                <td>3</td>
+                <td>Larry</td>
+                <td>the Bird</td>
+                <td>@twitter</td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+    <div class="col-md-6">
+        <table class="table table-striped">
+            <thead>
+            <tr>
+                <th>#</th>
+                <th>First Name</th>
+                <th>Last Name</th>
+                <th>Username</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr>
+                <td>1</td>
+                <td>Mark</td>
+                <td>Otto</td>
+                <td>@mdo</td>
+            </tr>
+            <tr>
+                <td>2</td>
+                <td>Jacob</td>
+                <td>Thornton</td>
+                <td>@fat</td>
+            </tr>
+            <tr>
+                <td>3</td>
+                <td>Larry</td>
+                <td>the Bird</td>
+                <td>@twitter</td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+</div>
+
+<div class="row">
+    <div class="col-md-6">
+        <table class="table table-bordered">
+            <thead>
+            <tr>
+                <th>#</th>
+                <th>First Name</th>
+                <th>Last Name</th>
+                <th>Username</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr>
+                <td rowspan="2">1</td>
+                <td>Mark</td>
+                <td>Otto</td>
+                <td>@mdo</td>
+            </tr>
+            <tr>
+                <td>Mark</td>
+                <td>Otto</td>
+                <td>@TwBootstrap</td>
+            </tr>
+            <tr>
+                <td>2</td>
+                <td>Jacob</td>
+                <td>Thornton</td>
+                <td>@fat</td>
+            </tr>
+            <tr>
+                <td>3</td>
+                <td colspan="2">Larry the Bird</td>
+                <td>@twitter</td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+    <div class="col-md-6">
+        <table class="table table-condensed">
+            <thead>
+            <tr>
+                <th>#</th>
+                <th>First Name</th>
+                <th>Last Name</th>
+                <th>Username</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr>
+                <td>1</td>
+                <td>Mark</td>
+                <td>Otto</td>
+                <td>@mdo</td>
+            </tr>
+            <tr>
+                <td>2</td>
+                <td>Jacob</td>
+                <td>Thornton</td>
+                <td>@fat</td>
+            </tr>
+            <tr>
+                <td>3</td>
+                <td colspan="2">Larry the Bird</td>
+                <td>@twitter</td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+</div>
+
+
+<div class="page-header">
+    <h1>Thumbnails</h1>
+</div>
+<img data-src="holder.js/200x200" class="img-thumbnail"
+     alt="A generic square placeholder image with a white border around it, making it resemble a photograph taken with an old instant camera">
+
+
+<div class="page-header">
+    <h1>Labels</h1>
+</div>
+<h1>
+    <span class="label label-default">Default</span>
+    <span class="label label-primary">Primary</span>
+    <span class="label label-success">Success</span>
+    <span class="label label-info">Info</span>
+    <span class="label label-warning">Warning</span>
+    <span class="label label-danger">Danger</span>
+</h1>
+
+<h2>
+    <span class="label label-default">Default</span>
+    <span class="label label-primary">Primary</span>
+    <span class="label label-success">Success</span>
+    <span class="label label-info">Info</span>
+    <span class="label label-warning">Warning</span>
+    <span class="label label-danger">Danger</span>
+</h2>
+
+<h3>
+    <span class="label label-default">Default</span>
+    <span class="label label-primary">Primary</span>
+    <span class="label label-success">Success</span>
+    <span class="label label-info">Info</span>
+    <span class="label label-warning">Warning</span>
+    <span class="label label-danger">Danger</span>
+</h3>
+<h4>
+    <span class="label label-default">Default</span>
+    <span class="label label-primary">Primary</span>
+    <span class="label label-success">Success</span>
+    <span class="label label-info">Info</span>
+    <span class="label label-warning">Warning</span>
+    <span class="label label-danger">Danger</span>
+</h4>
+<h5>
+    <span class="label label-default">Default</span>
+    <span class="label label-primary">Primary</span>
+    <span class="label label-success">Success</span>
+    <span class="label label-info">Info</span>
+    <span class="label label-warning">Warning</span>
+    <span class="label label-danger">Danger</span>
+</h5>
+<h6>
+    <span class="label label-default">Default</span>
+    <span class="label label-primary">Primary</span>
+    <span class="label label-success">Success</span>
+    <span class="label label-info">Info</span>
+    <span class="label label-warning">Warning</span>
+    <span class="label label-danger">Danger</span>
+</h6>
+
+<p>
+    <span class="label label-default">Default</span>
+    <span class="label label-primary">Primary</span>
+    <span class="label label-success">Success</span>
+    <span class="label label-info">Info</span>
+    <span class="label label-warning">Warning</span>
+    <span class="label label-danger">Danger</span>
+</p>
+
+
+<div class="page-header">
+    <h1>Badges</h1>
+</div>
+<p>
+    <a href="#">Inbox <span class="badge">42</span></a>
+</p>
+<ul class="nav nav-pills">
+    <li class="active"><a href="#">Home <span class="badge">42</span></a></li>
+    <li><a href="#">Profile</a></li>
+    <li><a href="#">Messages <span class="badge">3</span></a></li>
+</ul>
+
+
+<div class="page-header">
+    <h1>Dropdown menus</h1>
+</div>
+<div class="dropdown theme-dropdown clearfix">
+    <a id="dropdownMenu1" href="#" role="button" class="sr-only dropdown-toggle" data-toggle="dropdown">Dropdown <span
+            class="caret"></span></a>
+    <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
+        <li class="active" role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
+        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
+        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
+        <li role="presentation" class="divider"></li>
+        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
+    </ul>
+</div>
+
+
+<div class="page-header">
+    <h1>Navs</h1>
+</div>
+<ul class="nav nav-tabs" role="tablist">
+    <li class="active"><a href="#">Home</a></li>
+    <li><a href="#">Profile</a></li>
+    <li><a href="#">Messages</a></li>
+</ul>
+<ul class="nav nav-pills">
+    <li class="active"><a href="#">Home</a></li>
+    <li><a href="#">Profile</a></li>
+    <li><a href="#">Messages</a></li>
+</ul>
+
+
+<div class="page-header">
+    <h1>Navbars</h1>
+</div>
+
+<div class="navbar navbar-default">
+    <div class="container">
+        <div class="navbar-header">
+            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+                <span class="sr-only">Toggle navigation</span>
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+            </button>
+            <a class="navbar-brand" href="#">Project name</a>
+        </div>
+        <div class="navbar-collapse collapse">
+            <ul class="nav navbar-nav">
+                <li class="active"><a href="#">Home</a></li>
+                <li><a href="#about">About</a></li>
+                <li><a href="#contact">Contact</a></li>
+                <li class="dropdown">
+                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
+                    <ul class="dropdown-menu" role="menu">
+                        <li><a href="#">Action</a></li>
+                        <li><a href="#">Another action</a></li>
+                        <li><a href="#">Something else here</a></li>
+                        <li class="divider"></li>
+                        <li class="dropdown-header">Nav header</li>
+                        <li><a href="#">Separated link</a></li>
+                        <li><a href="#">One more separated link</a></li>
+                    </ul>
+                </li>
+            </ul>
+        </div>
+        <!--/.nav-collapse -->
+    </div>
+</div>
+
+<div class="navbar navbar-inverse">
+    <div class="container">
+        <div class="navbar-header">
+            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+                <span class="sr-only">Toggle navigation</span>
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+            </button>
+            <a class="navbar-brand" href="#">Project name</a>
+        </div>
+        <div class="navbar-collapse collapse">
+            <ul class="nav navbar-nav">
+                <li class="active"><a href="#">Home</a></li>
+                <li><a href="#about">About</a></li>
+                <li><a href="#contact">Contact</a></li>
+                <li class="dropdown">
+                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
+                    <ul class="dropdown-menu" role="menu">
+                        <li><a href="#">Action</a></li>
+                        <li><a href="#">Another action</a></li>
+                        <li><a href="#">Something else here</a></li>
+                        <li class="divider"></li>
+                        <li class="dropdown-header">Nav header</li>
+                        <li><a href="#">Separated link</a></li>
+                        <li><a href="#">One more separated link</a></li>
+                    </ul>
+                </li>
+            </ul>
+        </div>
+        <!--/.nav-collapse -->
+    </div>
+</div>
+
+
+<div class="page-header">
+    <h1>Alerts</h1>
+</div>
+<div class="alert alert-success" role="alert">
+    <strong>Well done!</strong> You successfully read this important alert message.
+</div>
+<div class="alert alert-info" role="alert">
+    <strong>Heads up!</strong> This alert needs your attention, but it's not super important.
+</div>
+<div class="alert alert-warning" role="alert">
+    <strong>Warning!</strong> Best check yo self, you're not looking too good.
+</div>
+<div class="alert alert-danger" role="alert">
+    <strong>Oh snap!</strong> Change a few things up and try submitting again.
+</div>
+
+
+<div class="page-header">
+    <h1>Progress bars</h1>
+</div>
+<div class="progress">
+    <div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"
+         style="width: 60%;"><span class="sr-only">60% Complete</span></div>
+</div>
+<div class="progress">
+    <div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0"
+         aria-valuemax="100" style="width: 40%"><span class="sr-only">40% Complete (success)</span></div>
+</div>
+<div class="progress">
+    <div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="20" aria-valuemin="0"
+         aria-valuemax="100" style="width: 20%"><span class="sr-only">20% Complete</span></div>
+</div>
+<div class="progress">
+    <div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="60" aria-valuemin="0"
+         aria-valuemax="100" style="width: 60%"><span class="sr-only">60% Complete (warning)</span></div>
+</div>
+<div class="progress">
+    <div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="80" aria-valuemin="0"
+         aria-valuemax="100" style="width: 80%"><span class="sr-only">80% Complete (danger)</span></div>
+</div>
+<div class="progress">
+    <div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="60" aria-valuemin="0"
+         aria-valuemax="100" style="width: 60%"><span class="sr-only">100% Complete</span></div>
+</div>
+<div class="progress">
+    <div class="progress-bar progress-bar-success" style="width: 35%"><span
+            class="sr-only">35% Complete (success)</span></div>
+    <div class="progress-bar progress-bar-warning" style="width: 20%"><span
+            class="sr-only">20% Complete (warning)</span></div>
+    <div class="progress-bar progress-bar-danger" style="width: 10%"><span class='sr-only'>10% Complete (danger)</span>
+    </div>
+</div>
+
+
+<div class="page-header">
+    <h1>List groups</h1>
+</div>
+<div class="row">
+    <div class="col-sm-4">
+        <ul class="list-group">
+            <li class="list-group-item">Cras justo odio</li>
+            <li class="list-group-item">Dapibus ac facilisis in</li>
+            <li class="list-group-item">Morbi leo risus</li>
+            <li class="list-group-item">Porta ac consectetur ac</li>
+            <li class="list-group-item">Vestibulum at eros</li>
+        </ul>
+    </div>
+    <!-- /.col-sm-4 -->
+    <div class="col-sm-4">
+        <div class="list-group">
+            <a href="#" class="list-group-item active">
+                Cras justo odio
+            </a>
+            <a href="#" class="list-group-item">Dapibus ac facilisis in</a>
+            <a href="#" class="list-group-item">Morbi leo risus</a>
+            <a href="#" class="list-group-item">Porta ac consectetur ac</a>
+            <a href="#" class="list-group-item">Vestibulum at eros</a>
+        </div>
+    </div>
+    <!-- /.col-sm-4 -->
+    <div class="col-sm-4">
+        <div class="list-group">
+            <a href="#" class="list-group-item active">
+                <h4 class="list-group-item-heading">List group item heading</h4>
+
+                <p class="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget
+                    risus varius blandit.</p>
+            </a>
+            <a href="#" class="list-group-item">
+                <h4 class="list-group-item-heading">List group item heading</h4>
+
+                <p class="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget
+                    risus varius blandit.</p>
+            </a>
+            <a href="#" class="list-group-item">
+                <h4 class="list-group-item-heading">List group item heading</h4>
+
+                <p class="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget
+                    risus varius blandit.</p>
+            </a>
+        </div>
+    </div>
+    <!-- /.col-sm-4 -->
+</div>
+
+
+<div class="page-header">
+    <h1>Panels</h1>
+</div>
+<div class="row">
+    <div class="col-sm-4">
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                <h3 class="panel-title">Panel title</h3>
+            </div>
+            <div class="panel-body">
+                Panel content
+            </div>
+        </div>
+        <div class="panel panel-primary">
+            <div class="panel-heading">
+                <h3 class="panel-title">Panel title</h3>
+            </div>
+            <div class="panel-body">
+                Panel content
+            </div>
+        </div>
+    </div>
+    <!-- /.col-sm-4 -->
+    <div class="col-sm-4">
+        <div class="panel panel-success">
+            <div class="panel-heading">
+                <h3 class="panel-title">Panel title</h3>
+            </div>
+            <div class="panel-body">
+                Panel content
+            </div>
+        </div>
+        <div class="panel panel-info">
+            <div class="panel-heading">
+                <h3 class="panel-title">Panel title</h3>
+            </div>
+            <div class="panel-body">
+                Panel content
+            </div>
+        </div>
+    </div>
+    <!-- /.col-sm-4 -->
+    <div class="col-sm-4">
+        <div class="panel panel-warning">
+            <div class="panel-heading">
+                <h3 class="panel-title">Panel title</h3>
+            </div>
+            <div class="panel-body">
+                Panel content
+            </div>
+        </div>
+        <div class="panel panel-danger">
+            <div class="panel-heading">
+                <h3 class="panel-title">Panel title</h3>
+            </div>
+            <div class="panel-body">
+                Panel content
+            </div>
+        </div>
+    </div>
+    <!-- /.col-sm-4 -->
+</div>
+
+
+<div class="page-header">
+    <h1>Wells</h1>
+</div>
+<div class="well">
+    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas sed diam eget risus varius blandit sit amet non
+        magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent commodo cursus magna, vel scelerisque
+        nisl consectetur et. Cras mattis consectetur purus sit amet fermentum. Duis mollis, est non commodo luctus, nisi
+        erat porttitor ligula, eget lacinia odio sem nec elit. Aenean lacinia bibendum nulla sed consectetur.</p>
+</div>
+
+
+</div>
+<!-- /container -->
+
+
+<!-- Bootstrap core JavaScript
+================================================== -->
+<!-- Placed at the end of the document so the pages load faster -->
+<script src="vendor/jquery/dist/jquery.min.js"></script>
+<script src="vendor/bootstrap/dist/js/bootstrap.min.js"></script>
+<script src="js/bootstrap-hadoop.min.js"></script>
+</body>
+</html>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/application/EmbeddedSolrServerFactory.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/application/EmbeddedSolrServerFactory.java
new file mode 100644
index 0000000..2a4b338
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/application/EmbeddedSolrServerFactory.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
+ *
+ *     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.appcatalog.application;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
+import org.apache.solr.client.solrj.request.CoreAdminRequest;
+import org.apache.solr.core.NodeConfig;
+import org.apache.solr.core.SolrResourceLoader;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Embedded solr server factory class for unit tests.
+ */
+public final class EmbeddedSolrServerFactory {
+
+  private EmbeddedSolrServerFactory() {
+  }
+
+  /**
+   * Cleans the given solrHome directory and creates a new EmbeddedSolrServer.
+   *
+   * @param solrHome
+   *          the Solr home directory to use
+   * @param configSetHome
+   *          the directory containing config sets
+   * @param coreName
+   *          the name of the core, must have a matching directory in configHome
+   *
+   * @return an EmbeddedSolrServer with a core created for the given coreName
+   * @throws IOException
+   */
+  public static SolrClient create(final String solrHome,
+      final String configSetHome, final String coreName)
+      throws IOException, SolrServerException {
+    return create(solrHome, configSetHome, coreName, true);
+  }
+
+  /**
+   * @param solrHome
+   *          the Solr home directory to use
+   * @param configSetHome
+   *          the directory containing config sets
+   * @param coreName
+   *          the name of the core, must have a matching directory in configHome
+   * @param cleanSolrHome
+   *          if true the directory for solrHome will be deleted and re-created
+   *          if it already exists
+   *
+   * @return an EmbeddedSolrServer with a core created for the given coreName
+   * @throws IOException
+   */
+  public static SolrClient create(final String solrHome,
+      final String configSetHome, final String coreName,
+      final boolean cleanSolrHome) throws IOException, SolrServerException {
+
+    final File solrHomeDir = new File(solrHome);
+    if (solrHomeDir.exists()) {
+      FileUtils.deleteDirectory(solrHomeDir);
+      solrHomeDir.mkdirs();
+    } else {
+      solrHomeDir.mkdirs();
+    }
+
+    final SolrResourceLoader loader = new SolrResourceLoader(
+        solrHomeDir.toPath());
+    final Path configSetPath = Paths.get(configSetHome).toAbsolutePath();
+
+    final NodeConfig config = new NodeConfig.NodeConfigBuilder(
+        "embeddedSolrServerNode", loader)
+            .setConfigSetBaseDirectory(configSetPath.toString()).build();
+
+    final EmbeddedSolrServer embeddedSolrServer = new EmbeddedSolrServer(config,
+        coreName);
+
+    final CoreAdminRequest.Create createRequest = new CoreAdminRequest.Create();
+    createRequest.setCoreName(coreName);
+    createRequest.setConfigSet(coreName);
+    embeddedSolrServer.request(createRequest);
+
+    return embeddedSolrServer;
+  }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/application/TestAppCatalogSolrClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/application/TestAppCatalogSolrClient.java
new file mode 100644
index 0000000..a43e0d4
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/application/TestAppCatalogSolrClient.java
@@ -0,0 +1,112 @@
+/*
+ * 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.appcatalog.application;
+
+import org.apache.hadoop.yarn.appcatalog.model.AppStoreEntry;
+import org.apache.hadoop.yarn.appcatalog.model.Application;
+import org.apache.solr.client.solrj.SolrClient;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.powermock.api.mockito.PowerMockito;
+import static org.powermock.api.mockito.PowerMockito.when;
+import static org.powermock.api.support.membermodification.MemberMatcher.method;
+
+import static org.junit.Assert.*;
+
+import java.util.List;
+
+/**
+ * Unit test for AppCatalogSolrClient.
+ */
+public class TestAppCatalogSolrClient {
+
+  static final String CONFIGSET_DIR = "src/test/resources/configsets";
+  private static SolrClient solrClient;
+  private static AppCatalogSolrClient spy;
+
+  @Before
+  public void setup() throws Exception {
+    String targetLocation = EmbeddedSolrServerFactory.class
+        .getProtectionDomain().getCodeSource().getLocation().getFile() + "/..";
+
+    String solrHome = targetLocation + "/solr";
+    solrClient = EmbeddedSolrServerFactory.create(solrHome, CONFIGSET_DIR,
+        "exampleCollection");
+    spy = PowerMockito.spy(new AppCatalogSolrClient());
+    when(spy, method(AppCatalogSolrClient.class, "getSolrClient"))
+        .withNoArguments().thenReturn(solrClient);
+  }
+
+  @After
+  public void teardown() throws Exception {
+    try {
+      solrClient.close();
+    } catch (Exception e) {
+    }
+  }
+
+  @Test
+  public void testRegister() throws Exception {
+    Application example = new Application();
+    example.setOrganization("jenkins-ci.org");
+    example.setName("jenkins");
+    example.setDescription("World leading open source automation system.");
+    example.setIcon("/css/img/feather.png");
+    spy.register(example);
+    List<AppStoreEntry> apps = spy.getRecommendedApps();
+    assertEquals(1, apps.size());
+  }
+
+  @Test
+  public void testSearch() throws Exception {
+    Application example = new Application();
+    example.setOrganization("jenkins-ci.org");
+    example.setName("jenkins");
+    example.setDescription("World leading open source automation system.");
+    example.setIcon("/css/img/feather.png");
+    spy.register(example);
+    List<AppStoreEntry> results = spy.search("name_s:jenkins");
+    int expected = 1;
+    int actual = results.size();
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testNotFoundSearch() throws Exception {
+    Application example = new Application();
+    example.setOrganization("jenkins-ci.org");
+    example.setName("jenkins");
+    example.setDescription("World leading open source automation system.");
+    example.setIcon("/css/img/feather.png");
+    spy.register(example);
+    List<AppStoreEntry> results = spy.search("name_s:abc");
+    int expected = 0;
+    int actual = results.size();
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testGetRecommendedApps() throws Exception {
+    List<AppStoreEntry> expected = spy.getRecommendedApps();
+    List<AppStoreEntry> actual = spy.getRecommendedApps();
+    assertEquals(expected, actual);
+  }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/controller/AppDetailsControllerTest.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/controller/AppDetailsControllerTest.java
new file mode 100644
index 0000000..ca4fba9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/controller/AppDetailsControllerTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.appcatalog.controller;
+
+import org.apache.hadoop.yarn.service.api.records.Service;
+import org.apache.hadoop.yarn.appcatalog.model.AppEntry;
+import org.apache.hadoop.yarn.service.api.records.Component;
+import org.apache.hadoop.yarn.service.api.records.Container;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit test for AppDetailsController.
+ */
+public class AppDetailsControllerTest {
+
+  private AppDetailsController controller;
+
+  @Before
+  public void setUp() throws Exception {
+    this.controller = new AppDetailsController();
+
+  }
+
+  @Test
+  public void testGetDetails() throws Exception {
+    String id = "application 1";
+    AppDetailsController ac = Mockito.mock(AppDetailsController.class);
+
+    AppEntry actual = new AppEntry();
+    actual.setName(id);
+    when(ac.getDetails(id)).thenReturn(actual);
+    final AppEntry result = ac.getDetails(id);
+    assertEquals(result, actual);
+  }
+
+  @Test
+  public void testGetStatus() throws Exception {
+    String id = "application 1";
+    AppDetailsController ac = Mockito.mock(AppDetailsController.class);
+
+    Service yarnfile = new Service();
+    Component comp = new Component();
+    Container c = new Container();
+    c.setId("container-1");
+    List<Container> containers = new ArrayList<Container>();
+    containers.add(c);
+    comp.setContainers(containers);
+    yarnfile.addComponent(comp);
+    AppEntry actual = new AppEntry();
+    actual.setName(id);
+    actual.setYarnfile(yarnfile);
+    when(ac.getStatus(id)).thenReturn(actual);
+    final AppEntry result = ac.getStatus(id);
+    assertEquals(result, actual);
+  }
+
+  @Test
+  public void testStopApp() throws Exception {
+    String id = "application 1";
+    AppDetailsController ac = Mockito.mock(AppDetailsController.class);
+
+    Service yarnfile = new Service();
+    Component comp = new Component();
+    Container c = new Container();
+    c.setId("container-1");
+    List<Container> containers = new ArrayList<Container>();
+    containers.add(c);
+    comp.setContainers(containers);
+    yarnfile.addComponent(comp);
+    Response expected = Response.ok().build();
+    when(ac.stopApp(id)).thenReturn(Response.ok().build());
+    final Response actual = ac.stopApp(id);
+    assertEquals(expected.getStatus(), actual.getStatus());
+  }
+
+  @Test
+  public void testRestartApp() throws Exception {
+    String id = "application 1";
+    AppDetailsController ac = Mockito.mock(AppDetailsController.class);
+
+    Service yarnfile = new Service();
+    Component comp = new Component();
+    Container c = new Container();
+    c.setId("container-1");
+    List<Container> containers = new ArrayList<Container>();
+    containers.add(c);
+    comp.setContainers(containers);
+    yarnfile.addComponent(comp);
+    Response expected = Response.ok().build();
+    when(ac.restartApp(id)).thenReturn(Response.ok().build());
+    final Response actual = ac.restartApp(id);
+    assertEquals(expected.getStatus(), actual.getStatus());
+  }
+
+  @Test
+  public void testPathAnnotation() throws Exception {
+    assertNotNull(this.controller.getClass()
+        .getAnnotations());
+    assertThat("The controller has the annotation Path",
+        this.controller.getClass()
+        .isAnnotationPresent(Path.class));
+
+    final Path path = this.controller.getClass()
+        .getAnnotation(Path.class);
+    assertThat("The path is /app_details", path.value(),
+        is("/app_details"));
+  }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/controller/AppListControllerTest.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/controller/AppListControllerTest.java
new file mode 100644
index 0000000..97f288e
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/controller/AppListControllerTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.appcatalog.controller;
+
+import org.apache.hadoop.yarn.appcatalog.model.AppEntry;
+import org.apache.hadoop.yarn.service.api.records.Service;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit test for AppListController.
+ */
+public class AppListControllerTest {
+
+  private AppListController controller;
+
+  @Before
+  public void setUp() throws Exception {
+    this.controller = new AppListController();
+
+  }
+
+  @Test
+  public void testGetList() throws Exception {
+    AppListController ac = Mockito.mock(AppListController.class);
+
+    List<AppEntry> actual = new ArrayList<AppEntry>();
+    when(ac.getList()).thenReturn(actual);
+    final List<AppEntry> result = ac.getList();
+    assertEquals(result, actual);
+  }
+
+  @Test
+  public void testDelete() throws Exception {
+    String id = "application 1";
+    AppListController ac = Mockito.mock(AppListController.class);
+
+    Response expected = Response.ok().build();
+    when(ac.delete(id, id)).thenReturn(Response.ok().build());
+    final Response actual = ac.delete(id, id);
+    assertEquals(expected.getStatus(), actual.getStatus());
+  }
+
+  @Test
+  public void testDeploy() throws Exception {
+    String id = "application 1";
+    AppListController ac = Mockito.mock(AppListController.class);
+    Service service = new Service();
+    Response expected = Response.ok().build();
+    when(ac.deploy(id, service)).thenReturn(Response.ok().build());
+    final Response actual = ac.deploy(id, service);
+    assertEquals(expected.getStatus(), actual.getStatus());
+  }
+
+  @Test
+  public void testPathAnnotation() throws Exception {
+    assertNotNull(this.controller.getClass()
+        .getAnnotations());
+    assertThat("The controller has the annotation Path",
+        this.controller.getClass().isAnnotationPresent(Path.class));
+
+    final Path path = this.controller.getClass()
+        .getAnnotation(Path.class);
+    assertThat("The path is /app_list", path.value(), is("/app_list"));
+  }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/controller/AppStoreControllerTest.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/controller/AppStoreControllerTest.java
new file mode 100644
index 0000000..d09952b
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/java/org/apache/hadoop/yarn/appcatalog/controller/AppStoreControllerTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.appcatalog.controller;
+
+import org.apache.hadoop.yarn.appcatalog.model.AppStoreEntry;
+import org.apache.hadoop.yarn.appcatalog.model.Application;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit tests for AppStoreController.
+ */
+public class AppStoreControllerTest {
+
+  private AppStoreController controller;
+
+  @Before
+  public void setUp() throws Exception {
+    this.controller = new AppStoreController();
+
+  }
+
+  @Test
+  public void testGetRecommended() throws Exception {
+    AppStoreController ac = Mockito.mock(AppStoreController.class);
+    List<AppStoreEntry> actual = new ArrayList<AppStoreEntry>();
+    when(ac.get()).thenReturn(actual);
+    final List<AppStoreEntry> result = ac.get();
+    assertEquals(result, actual);
+  }
+
+  @Test
+  public void testSearch() throws Exception {
+    String keyword = "jenkins";
+    AppStoreController ac = Mockito.mock(AppStoreController.class);
+    List<AppStoreEntry> expected = new ArrayList<AppStoreEntry>();
+    when(ac.search(keyword)).thenReturn(expected);
+    final List<AppStoreEntry> actual = ac.search(keyword);
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testRegister() throws Exception {
+    AppStoreController ac = Mockito.mock(AppStoreController.class);
+    Application app = new Application();
+    app.setName("jenkins");
+    app.setOrganization("jenkins.org");
+    app.setDescription("This is a description");
+    app.setIcon("/css/img/feather.png");
+    Response expected = Response.ok().build();
+    when(ac.register(app)).thenReturn(Response.ok().build());
+    final Response actual = ac.register(app);
+    assertEquals(expected.getStatus(), actual.getStatus());
+  }
+
+  @Test
+  public void testPathAnnotation() throws Exception {
+    assertNotNull(this.controller.getClass()
+        .getAnnotations());
+    assertThat("The controller has the annotation Path",
+        this.controller.getClass()
+        .isAnnotationPresent(Path.class));
+
+    final Path path = this.controller.getClass()
+        .getAnnotation(Path.class);
+    assertThat("The path is /app_store", path.value(), is("/app_store"));
+  }
+
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/javascript/controllersSpec.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/javascript/controllersSpec.js
new file mode 100644
index 0000000..ec58934
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/javascript/controllersSpec.js
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ */
+
+describe('Controller tests', function () {
+
+  // Unit test for listing, and start/stop applications.
+  describe('AppListController', function() {
+    var scope, ctrl, http, httpBackend;
+
+    beforeEach(module('app'));
+    beforeEach(inject(function ($controller, $rootScope, $http, $httpBackend) {
+      scope = $rootScope.$new();
+      rootScope = $rootScope;
+      http = $http;
+      httpBackend = $httpBackend;
+      ctrl = $controller('AppListController', {$scope: scope});
+    }));
+
+    afterEach(function() {
+      httpBackend.verifyNoOutstandingExpectation();
+      httpBackend.verifyNoOutstandingRequest();
+    });
+
+    it('should contain appList', function () {
+      httpBackend.expectGET('/v1/app_list').respond(200, [{id:"jenkins",name:"jenkins",app:"",yarnfile:{}}]);
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      httpBackend.flush();
+      expect(scope.appList.length).toBe(1);
+    });
+
+    it('should test to delete app', function () {
+      httpBackend.expectGET('/v1/app_list').respond(200, [{id:"jenkins",name:"jenkins",app:"",yarnfile:{}}]);
+      httpBackend.expectDELETE('/v1/app_list/jenkins/jenkins').respond(200, {data:"Application Deleted."});
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      spyOn(rootScope, '$emit');
+      scope.$apply(function() {
+        scope.deleteApp("jenkins","jenkins");
+      });
+      httpBackend.flush();
+      expect(rootScope.$emit).toHaveBeenCalledWith('RefreshAppList', {});
+    });
+
+    it('should test to refresh appList', function() {
+      spyOn(rootScope, '$emit');
+      httpBackend.expectGET('/v1/app_list').respond(200, [{id:"jenkins",name:"jenkins",app:"",yarnfile:{}}]);
+      httpBackend.expectGET('/v1/app_list').respond(200, [{id:"jenkins",name:"jenkins",app:"",yarnfile:{}}]);
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      scope.$apply(function() {
+        scope.refreshList();
+      });
+      httpBackend.flush();
+      expect(rootScope.$emit).toHaveBeenCalledWith('hideLoadScreen', {});
+    })
+  });
+
+  // Unit test for inspect YARN application details.
+  describe('AppDetailsController', function() {
+    var scope, ctrl, http, routeParams, httpBackend;
+
+    beforeEach(module('app'));
+    beforeEach(inject(function ($controller, $rootScope, $http, $routeParams, $httpBackend) {
+      scope = $rootScope.$new();
+      rootScope = $rootScope;
+      http = $http;
+      routeParams = $routeParams;
+      httpBackend = $httpBackend;
+      ctrl = $controller('AppDetailsController', {$scope: scope});
+    }));
+
+    afterEach(function() {
+      httpBackend.verifyNoOutstandingExpectation();
+      httpBackend.verifyNoOutstandingRequest();
+    });
+
+    it('should contain unknown state', function () {
+      httpBackend.expectGET('/v1/app_details/config/undefined').respond(200, {"yarnfile":{"state":"UNKNOWN","components":[]}});
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      httpBackend.flush();
+      expect(scope.details.yarnfile.state).toBe("UNKNOWN");
+    });
+
+    it('should run test to refrshed details', function () {
+      httpBackend.expectGET('/v1/app_details/config/undefined').respond(200, {"yarnfile":{"state":"UNKNOWN","components":[]}});
+      httpBackend.expectGET('/v1/app_details/status/aabbccdd').respond(200, {yarnfile:{state: "ACCEPTED", components:[]}});
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      scope.$apply(function() {
+        routeParams.id = "aabbccdd";
+        scope.appName = "aabbccdd";
+        scope.refreshAppDetails();
+      });
+      httpBackend.flush();
+      expect(scope.details.yarnfile.state).toBe("ACCEPTED");
+    });
+
+    it('should run test to restart app', function () {
+      httpBackend.expectGET('/v1/app_details/config/undefined').respond(200, {"yarnfile":{"state":"UNKNOWN","components":[]}});
+      httpBackend.expectPOST('/v1/app_details/restart/aabbccdd').respond(200, {yarnfile:{state: "ACCEPTED", components:[]}});
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      httpBackend.expectGET('/v1/app_details/status/undefined').respond(200, {yarnfile:{state: "ACCEPTED", components:[]}});
+      scope.$apply(function() {
+        scope.restartApp("aabbccdd");
+      });
+      httpBackend.flush();
+      expect(scope.details.yarnfile.components).toBe();
+    });
+
+    it('should run test to stop app', function () {
+      httpBackend.expectGET('/v1/app_details/config/undefined').respond(200, {"yarnfile":{"state":"UNKNOWN","components":[]}});
+      httpBackend.expectPOST('/v1/app_details/stop/aabbccdd').respond(200, {yarnfile:{state: "STOPPED", components:[]}});
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      httpBackend.expectGET('/v1/app_details/status/undefined').respond(200, {yarnfile:{state: "ACCEPTED", components:[]}});
+      scope.$apply(function() {
+        scope.stopApp("aabbccdd");
+      });
+      httpBackend.flush();
+      expect(scope.details.yarnfile.components).toBe();
+    });
+
+  });
+
+  // Unit test for deploying app, and search for apps from Yarn Appstore.
+  describe('AppStoreController', function() {
+    var scope, ctrl, http, httpBackend;
+
+    beforeEach(module('app'));
+    beforeEach(inject(function ($controller, $rootScope, $http, $httpBackend) {
+      scope = $rootScope.$new();
+      http = $http;
+      httpBackend = $httpBackend;
+      ctrl = $controller('AppStoreController', {$scope: scope});
+    }));
+
+    afterEach(function() {
+      httpBackend.verifyNoOutstandingExpectation();
+      httpBackend.verifyNoOutstandingRequest();
+    });
+
+    it('should contain appStore', function () {
+      httpBackend.expectGET('/v1/app_store/recommended').respond(200, "");
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      httpBackend.flush();
+      expect(scope.appStore.length).toBe(0);
+    });
+
+    it('should run test to deploy app', function() {
+      httpBackend.expectGET('/v1/app_store/recommended').respond(200, "");
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      httpBackend.flush();
+      scope.$apply(function() {
+        scope.deployApp("aabbccdd");
+      });
+      expect(scope.appStore.length).toBe(0);
+    });
+
+    it('should run test to search for apps', function() {
+      httpBackend.expectGET('/v1/app_store/recommended').respond(200, "");
+      httpBackend.expectGET('/v1/app_store/search?q=aabbccdd').respond(204, {data:'ACCEPTED'});
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      scope.$apply(function() {
+        scope.searchText = "aabbccdd";
+        scope.change("aabbccdd");
+      });
+      httpBackend.flush();
+      expect(scope.appStore.data).toBe('ACCEPTED');
+    });
+
+  });
+
+  // Unit test cases for creating a new YARN application.
+  describe('NewAppController', function() {
+    var scope, ctrl, http, httpBackend;
+
+    beforeEach(module('app'));
+    beforeEach(inject(function ($controller, $rootScope, $http, $httpBackend) {
+      scope = $rootScope.$new();
+      http = $http;
+      httpBackend = $httpBackend;
+      ctrl = $controller('NewAppController', {$scope: scope});
+    }));
+
+    afterEach(function() {
+      httpBackend.verifyNoOutstandingExpectation();
+      httpBackend.verifyNoOutstandingRequest();
+    });
+
+    it('should contain details', function () {
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      httpBackend.flush();
+      expect(scope.details.name).toBe("");
+    });
+
+    it('should run test to register data to backend', function() {
+      httpBackend.expectPOST('/v1/app_store/register').respond(204, {data:'ACCEPTED'});
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      scope.$apply(function() {
+        scope.save();
+      });
+      httpBackend.flush();
+      expect(scope.message).toEqual("Application published successfully.");
+    });
+
+    it('should run test to fail register data to backend', function() {
+      httpBackend.expectPOST('/v1/app_store/register').respond(500, {data:'INTERNAL SERVER ERROR'});
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      scope.$apply(function() {
+        scope.save();
+      });
+      httpBackend.flush();
+      expect(scope.error).toEqual("Error in registering application configuration.");
+    });
+
+    it('should run test to add more component to details', function() {
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      expect(scope.details.components.length).toEqual(1);
+      scope.$apply(function() {
+        scope.add();
+      });
+      httpBackend.flush();
+      expect(scope.details.components.length).toEqual(2);
+    });
+
+    it('should run test to remove second component', function() {
+      httpBackend.expectGET('partials/home.html').respond(200, "");
+      expect(scope.details.components.length).toEqual(1);
+      scope.$apply(function() {
+        scope.add();
+        scope.remove(1);
+      });
+      httpBackend.flush();
+      expect(scope.details.components.length).toEqual(1);
+    });
+  });
+
+});
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/javascript/karma.conf.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/javascript/karma.conf.js
new file mode 100644
index 0000000..f7620a4
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/javascript/karma.conf.js
@@ -0,0 +1,34 @@
+module.exports = function(config){
+  config.set({
+
+    basePath : '../../../',
+
+    files : [
+      'target/generated-sources/vendor/angular**/**.min.js',
+      'target/generated-sources/vendor/angular-mocks/angular-mocks.js',
+      'src/main/javascript/**/*.js',
+      'src/test/javascript/**/*Spec.js',
+      'src/test/javascript/**/!(karma.conf).js'
+    ],
+
+    autoWatch : true,
+
+    frameworks: ['jasmine'],
+
+                 browsers: ['PhantomJS'],
+
+    plugins : [
+            'karma-chrome-launcher',
+            'karma-firefox-launcher',
+            'karma-phantomjs-launcher',
+            'karma-jasmine',
+            'karma-junit-reporter'
+            ],
+
+    junitReporter : {
+      outputFile: 'target/test_out/unit.xml',
+        suite: 'src/test/javascript'
+    }
+
+  });
+};
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets.tgz b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets.tgz
new file mode 100644
index 0000000..3352d31
Binary files /dev/null and b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets.tgz differ
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/lang/stopwords_en.txt b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/lang/stopwords_en.txt
new file mode 100644
index 0000000..2c164c0
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/lang/stopwords_en.txt
@@ -0,0 +1,54 @@
+# 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.
+
+# a couple of test stopwords to test that the words are really being
+# configured from this file:
+stopworda
+stopwordb
+
+# Standard english stop words taken from Lucene's StopAnalyzer
+a
+an
+and
+are
+as
+at
+be
+but
+by
+for
+if
+in
+into
+is
+it
+no
+not
+of
+on
+or
+such
+that
+the
+their
+then
+there
+these
+they
+this
+to
+was
+will
+with
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/params.json b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/params.json
new file mode 100644
index 0000000..06114ef
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/params.json
@@ -0,0 +1,20 @@
+{"params":{
+  "query":{
+    "defType":"edismax",
+    "q.alt":"*:*",
+    "rows":"10",
+    "fl":"*,score",
+    "":{"v":0}
+  },
+  "facets":{
+    "facet":"on",
+    "facet.mincount": "1",
+    "":{"v":0}
+  },
+ "velocity":{
+   "wt": "velocity",
+   "v.template":"browse",
+   "v.layout": "layout",
+   "":{"v":0}
+ }
+}}
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/protwords.txt b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/protwords.txt
new file mode 100644
index 0000000..4341c05
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/protwords.txt
@@ -0,0 +1,20 @@
+# 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.
+
+#-----------------------------------------------------------------------
+# Use a protected word file to protect against the stemmer reducing two
+# unrelated words to the same base word.
+
+# Some non-words that normally won't be encountered,
+# just to test that they won't be stemmed.
+dontstems
+zwhacky
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/schema.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/schema.xml
new file mode 100644
index 0000000..20acbc9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/schema.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<schema name="exampleCollection" version="1.6">
+
+    <!-- Defined fields -->
+    <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" docValues="true" />
+    <field name="type_s" type="string" indexed="true" stored="true" required="false" multiValued="false" docValues="true" />
+    <field name="org_s" type="string" indexed="true" stored="true" required="false" multiValued="false" docValues="true" />
+    <field name="name_s" type="string" indexed="true" stored="true" required="false" multiValued="false" docValues="true" />
+    <field name="desc_s" type="string" indexed="true" stored="true" required="false" multiValued="false" docValues="true" />
+    <field name="icon_s" type="string" indexed="true" stored="true" required="false" multiValued="false" docValues="true" />
+    <field name="yarnfile_s" type="string" indexed="true" stored="true" required="false" multiValued="false" docValues="true" />
+    <field name="like_i" type="int" indexed="true" stored="true" required="false" multiValued="false" docValues="true" />
+    <field name="download_i" type="int" indexed="true" stored="true" required="false" multiValued="false" docValues="true" />
+    <field name="_version_" type="long" indexed="true" stored="false"/>
+
+    <uniqueKey>id</uniqueKey>
+
+    <!-- Field types -->
+    <fieldType name="string" class="solr.StrField" sortMissingLast="true" docValues="true" />
+    <fieldType name="strings" class="solr.StrField" sortMissingLast="true" multiValued="true" docValues="true" />
+    <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
+    <fieldType name="booleans" class="solr.BoolField" sortMissingLast="true" multiValued="true"/>
+    <fieldType name="int" class="solr.TrieIntField" docValues="true" precisionStep="0" positionIncrementGap="0"/>
+    <fieldType name="float" class="solr.TrieFloatField" docValues="true" precisionStep="0" positionIncrementGap="0"/>
+    <fieldType name="long" class="solr.TrieLongField" docValues="true" precisionStep="0" positionIncrementGap="0"/>
+    <fieldType name="double" class="solr.TrieDoubleField" docValues="true" precisionStep="0" positionIncrementGap="0"/>
+    <fieldType name="ints" class="solr.TrieIntField" docValues="true" precisionStep="0" positionIncrementGap="0" multiValued="true"/>
+    <fieldType name="floats" class="solr.TrieFloatField" docValues="true" precisionStep="0" positionIncrementGap="0" multiValued="true"/>
+    <fieldType name="longs" class="solr.TrieLongField" docValues="true" precisionStep="0" positionIncrementGap="0" multiValued="true"/>
+    <fieldType name="doubles" class="solr.TrieDoubleField" docValues="true" precisionStep="0" positionIncrementGap="0" multiValued="true"/>
+    <fieldType name="tint" class="solr.TrieIntField" docValues="true" precisionStep="8" positionIncrementGap="0"/>
+    <fieldType name="tfloat" class="solr.TrieFloatField" docValues="true" precisionStep="8" positionIncrementGap="0"/>
+    <fieldType name="tlong" class="solr.TrieLongField" docValues="true" precisionStep="8" positionIncrementGap="0"/>
+    <fieldType name="tdouble" class="solr.TrieDoubleField" docValues="true" precisionStep="8" positionIncrementGap="0"/>
+    <fieldType name="tints" class="solr.TrieIntField" docValues="true" precisionStep="8" positionIncrementGap="0" multiValued="true"/>
+    <fieldType name="tfloats" class="solr.TrieFloatField" docValues="true" precisionStep="8" positionIncrementGap="0" multiValued="true"/>
+    <fieldType name="tlongs" class="solr.TrieLongField" docValues="true" precisionStep="8" positionIncrementGap="0" multiValued="true"/>
+    <fieldType name="tdoubles" class="solr.TrieDoubleField" docValues="true" precisionStep="8" positionIncrementGap="0" multiValued="true"/>
+    <fieldType name="date" class="solr.TrieDateField" docValues="true" precisionStep="0" positionIncrementGap="0"/>
+    <fieldType name="dates" class="solr.TrieDateField" docValues="true" precisionStep="0" positionIncrementGap="0" multiValued="true"/>
+    <fieldType name="tdate" class="solr.TrieDateField" docValues="true" precisionStep="6" positionIncrementGap="0"/>
+    <fieldType name="tdates" class="solr.TrieDateField" docValues="true" precisionStep="6" positionIncrementGap="0" multiValued="true"/>
+    <fieldType name="binary" class="solr.BinaryField"/>
+    <fieldType name="random" class="solr.RandomSortField" indexed="true" />
+
+    <!-- A text field with defaults appropriate for English: it
+         tokenizes with StandardTokenizer, removes English stop words
+         (lang/stopwords_en.txt), down cases, protects words from protwords.txt, and
+         finally applies Porter's stemming.  The query time analyzer
+         also applies synonyms from synonyms.txt. -->
+    <fieldType name="text_en" class="solr.TextField" positionIncrementGap="100">
+      <analyzer type="index">
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <!-- in this example, we will only use synonyms at query time
+        <filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/> -->
+        <!-- Case insensitive stop word removal. -->
+        <filter class="solr.StopFilterFactory"
+                ignoreCase="true"
+                words="lang/stopwords_en.txt"
+            />
+        <filter class="solr.LowerCaseFilterFactory"/>
+        <filter class="solr.EnglishPossessiveFilterFactory"/>
+        <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
+        <!-- Optionally you may want to use this less aggressive stemmer instead of PorterStemFilterFactory:
+        <filter class="solr.EnglishMinimalStemFilterFactory"/>
+        -->
+        <filter class="solr.PorterStemFilterFactory"/>
+      </analyzer>
+      <analyzer type="query">
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
+        <filter class="solr.StopFilterFactory"
+                ignoreCase="true"
+                words="lang/stopwords_en.txt"
+        />
+        <filter class="solr.LowerCaseFilterFactory"/>
+        <filter class="solr.EnglishPossessiveFilterFactory"/>
+        <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
+        <!-- Optionally you may want to use this less aggressive stemmer instead of PorterStemFilterFactory:
+        <filter class="solr.EnglishMinimalStemFilterFactory"/>
+        -->
+        <filter class="solr.PorterStemFilterFactory"/>
+      </analyzer>
+    </fieldType>
+
+    <!-- lowercases the entire field value, keeping it as a single token.  -->
+    <fieldType name="lowercase" class="solr.TextField" positionIncrementGap="100">
+      <analyzer>
+        <tokenizer class="solr.KeywordTokenizerFactory"/>
+        <filter class="solr.LowerCaseFilterFactory" />
+      </analyzer>
+    </fieldType>
+
+    <!-- since fields of this type are by default not stored or indexed,
+         any data added to them will be ignored outright.  -->
+    <fieldType name="ignored" stored="false" indexed="false" docValues="false" multiValued="true" class="solr.StrField" />
+
+</schema>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/solrconfig.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/solrconfig.xml
new file mode 100644
index 0000000..392feec
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/solrconfig.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+<config>
+  <luceneMatchVersion>6.2.1</luceneMatchVersion>
+
+  <dataDir>${solr.data.dir:}</dataDir>
+
+  <schemaFactory class="ClassicIndexSchemaFactory"/>
+
+  <indexConfig>
+    <lockType>single</lockType>
+  </indexConfig>
+
+  <requestDispatcher handleSelect="false">
+    <httpCaching never304="true" />
+  </requestDispatcher>
+
+  <requestHandler name="/select" class="solr.SearchHandler" />
+  <requestHandler name="/update" class="solr.UpdateRequestHandler" />
+
+</config>
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/stopwords.txt b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/stopwords.txt
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/stopwords.txt
@@ -0,0 +1,14 @@
+# 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.
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/synonyms.txt b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/synonyms.txt
new file mode 100644
index 0000000..0ef0e8d
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/configsets/exampleCollection/conf/synonyms.txt
@@ -0,0 +1,28 @@
+# 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.
+
+#-----------------------------------------------------------------------
+#some test synonym mappings unlikely to appear in real input text
+aaafoo => aaabar
+bbbfoo => bbbfoo bbbbar
+cccfoo => cccbar cccbaz
+fooaaa,baraaa,bazaaa
+
+# Some synonym groups specific to this example
+GB,gib,gigabyte,gigabytes
+MB,mib,megabyte,megabytes
+Television, Televisions, TV, TVs
+#notice we use "gib" instead of "GiB" so any WordDelimiterFilter coming
+#after us won't split it into two words.
+
+# Synonym mappings can be used for spelling correction too
+pixima => pixma
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/log4j.properties b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/log4j.properties
new file mode 100644
index 0000000..eb04743
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/hadoop-yarn-applications-catalog-webapp/src/test/resources/log4j.properties
@@ -0,0 +1,11 @@
+log4j.rootLogger = INFO, CATALINA
+
+# Define all the appenders
+log4j.appender.CATALINA = org.apache.log4j.DailyRollingFileAppender
+log4j.appender.CATALINA.File = target/appcatalog.log
+log4j.appender.CATALINA.Append = true
+log4j.appender.CATALINA.Encoding = UTF-8
+# Roll-over the log once per day
+log4j.appender.CATALINA.DatePattern = '.'yyyy-MM-dd'.log'
+log4j.appender.CATALINA.layout = org.apache.log4j.PatternLayout
+log4j.appender.CATALINA.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/pom.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/pom.xml
new file mode 100644
index 0000000..770bf24
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-applications-catalog/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+-->
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>hadoop-yarn-applications</artifactId>
+        <groupId>org.apache.hadoop</groupId>
+        <version>3.3.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.hadoop</groupId>
+    <artifactId>hadoop-yarn-applications-catalog</artifactId>
+    <packaging>pom</packaging>
+
+    <name>YARN Application Catalog</name>
+
+    <url>http://hadoop.apache.org</url>
+
+    <modules>
+      <module>hadoop-yarn-applications-catalog-webapp</module>
+      <module>hadoop-yarn-applications-catalog-docker</module>
+    </modules>
+</project>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-api/src/main/java/org/apache/hadoop/yarn/service/client/ApiServiceClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-api/src/main/java/org/apache/hadoop/yarn/service/client/ApiServiceClient.java
index 94f03c3..834bb03 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-api/src/main/java/org/apache/hadoop/yarn/service/client/ApiServiceClient.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-api/src/main/java/org/apache/hadoop/yarn/service/client/ApiServiceClient.java
@@ -77,6 +77,13 @@ public class ApiServiceClient extends AppAdminClient {
   private static final Base64 BASE_64_CODEC = new Base64(0);
   protected YarnClient yarnClient;
 
+  public ApiServiceClient() {
+  }
+
+  public ApiServiceClient(Configuration c) throws Exception {
+    serviceInit(c);
+  }
+
   @Override protected void serviceInit(Configuration configuration)
       throws Exception {
     yarnClient = YarnClient.createYarnClient();
@@ -151,7 +158,7 @@ public class ApiServiceClient extends AppAdminClient {
    * @return URI to API Service
    * @throws IOException
    */
-  protected String getServicePath(String appName) throws IOException {
+  public String getServicePath(String appName) throws IOException {
     String url = getRMWebAddress();
     StringBuilder api = new StringBuilder();
     api.append(url)
@@ -215,7 +222,7 @@ public class ApiServiceClient extends AppAdminClient {
     }
   }
 
-  private Builder getApiClient() throws IOException {
+  public Builder getApiClient() throws IOException {
     return getApiClient(getServicePath(null));
   }
 
@@ -226,7 +233,7 @@ public class ApiServiceClient extends AppAdminClient {
    * @return
    * @throws IOException
    */
-  private Builder getApiClient(String requestPath)
+  public Builder getApiClient(String requestPath)
       throws IOException {
     Client client = Client.create(getClientConfig());
     client.setChunkedEncodingSize(null);
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/appcatalog/appcatalog.json b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/appcatalog/appcatalog.json
new file mode 100755
index 0000000..6a5f2f3
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/examples/appcatalog/appcatalog.json
@@ -0,0 +1,28 @@
+{
+  "name": "appcatalog",
+  "version": "1",
+  "components" :
+  [
+    {
+      "name": "catalog",
+      "number_of_containers": 1,
+      "artifact": {
+        "id": "apache/hadoop-yarn-applications-catalog-docker:3.3.0-SNAPSHOT",
+        "type": "DOCKER"
+      },
+      "resource": {
+        "cpus": 1,
+        "memory": "2048"
+      },
+      "configuration": {
+        "env": {
+          "YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE":"true",
+          "YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS":"/etc/hadoop/conf:/etc/hadoop/conf:ro,/var/lib/sss/pipes:/var/lib/sss/pipes:rw",
+          "JAVA_HOME":"/usr/lib/jvm/jre-1.8.0"
+        },
+        "properties": {
+        }
+      }
+    }
+  ]
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/pom.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/pom.xml
index 61ca77a..78b709a 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/pom.xml
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/pom.xml
@@ -37,6 +37,7 @@
     <module>hadoop-yarn-applications-distributedshell</module>
     <module>hadoop-yarn-applications-unmanaged-am-launcher</module>
     <module>hadoop-yarn-services</module>
+    <module>hadoop-yarn-applications-catalog</module>
   </modules>
 
  <profiles>
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/yarn-service/Examples.md b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/yarn-service/Examples.md
index da7a9c4..e0d1c01 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/yarn-service/Examples.md
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/yarn-service/Examples.md
@@ -165,6 +165,19 @@ where `service-name` is optional. If omitted, it uses the name defined in the `Y
 Look up your IPs at the RM REST endpoint `http://<RM host>:8088/app/v1/services/httpd-service`.
 Then visit port 8080 for each IP to view the pages.
 
+## Application Catalog - appcatalog
+
+Application Catalog introduces many exciting new features for deploying Hadoop software that benefit both administrators and end users.  With Application Catalog, user gets a personalized view of the software status in Hadoop.  In addition, users can install or register applications by using web-based user interface.
+
+To start Application Catalog service with the command:
+```
+yarn app -launch <service-name> appcatalog
+```
+where `service-name` is user defined name.
+
+The deployment progress of the application catalog is located in Resource Manager UI.  When the service reaches STABLE state, application catalog UI is available at:
+http://appcatalog.${SERVICE_NAME}.${USER}.${DOMAIN}:8080/
+
 ## Docker image ENTRYPOINT support
 
 Docker images may have built with ENTRYPOINT to enable start up of docker image without any parameters.


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