You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jl...@apache.org on 2016/06/27 23:36:27 UTC

[01/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Repository: ambari
Updated Branches:
  refs/heads/branch-yarnapps-dev 270c23fb1 -> b88db3cc0


http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/view.log4j.properties
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/view.log4j.properties b/contrib/views/hive-next/src/main/resources/view.log4j.properties
new file mode 100644
index 0000000..b1bd5f2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/view.log4j.properties
@@ -0,0 +1,31 @@
+# Copyright 2011 The Apache Software Foundation
+#
+# 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.
+
+log4j.appender.hiveNextView=org.apache.log4j.RollingFileAppender
+log4j.appender.hiveNextView.File=/var/log/ambari-server/hive-next-view/hive-view.log
+log4j.appender.hiveNextView.MaxFileSize=80MB
+log4j.appender.hiveNextView.MaxBackupIndex=60
+log4j.appender.hiveNextView.layout=org.apache.log4j.PatternLayout
+log4j.appender.hiveNextView.layout.ConversionPattern=%d{DATE} %5p [%t] %c{1}:%L - %m%n
+
+log4j.logger.org.apache.ambari.view.hive2=INFO,hiveNextView
+log4j.logger.org.apache.hive.jdbc=INFO,hiveNextView
+log4j.logger.akka.actor=INFO,hiveNextView
+log4j.additivity.org.apache.ambari.view.hive2 = false
+log4j.additivity.org.apache.hive.jdbc = false
+log4j.additivity.akka.actor = false

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/view.xml
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/view.xml b/contrib/views/hive-next/src/main/resources/view.xml
new file mode 100644
index 0000000..c2d2dc5
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/view.xml
@@ -0,0 +1,298 @@
+<!--
+   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.
+-->
+<view>
+    <name>HIVE</name>
+    <label>Hive</label>
+    <version>2.0.0</version>
+    <build>${env.BUILD_NUMBER}</build>
+
+    <min-ambari-version>2.0.*</min-ambari-version>
+
+    <validator-class>org.apache.ambari.view.hive2.PropertyValidator</validator-class>
+    <view-class>org.apache.ambari.view.hive2.HiveViewImpl</view-class>
+
+    <!-- Hive Configs -->
+    <parameter>
+      <name>hive.jdbc.url</name>
+      <description>Enter JDBC Url to connect to Hive Server 2</description>
+      <label>HiveServer2 JDBC Url</label>
+      <placeholder>jdbc:hive2://127.0.0.1:10000</placeholder>
+      <cluster-config>fake</cluster-config>
+      <required>true</required>
+    </parameter>
+
+    <parameter>
+      <name>hive.session.params</name>
+      <description>Semicolon-separated key value parameters to be used in JDBC URL generation to connect to hive server 2</description>
+      <label>Hive Session Parameters</label>
+      <placeholder>transportMode=http;httpPath=cliservice</placeholder>
+      <default-value></default-value>
+      <required>false</required>
+    </parameter>
+
+    <parameter>
+        <name>hive.metastore.warehouse.dir</name>
+        <description>Hive Metastore directory (example: /apps/hive/warehouse)</description>
+        <label>Hive Metastore directory</label>
+        <placeholder>/apps/hive/warehouse</placeholder>
+        <default-value>/apps/hive/warehouse</default-value>
+        <cluster-config>hive-site/hive.metastore.warehouse.dir</cluster-config>
+        <required>false</required>
+    </parameter>
+
+    <!-- HDFS Configs -->
+    <parameter>
+        <name>webhdfs.url</name>
+        <description>Enter the WebHDFS FileSystem URI. Typically this is the dfs.namenode.http-address
+            property in the hdfs-site.xml configuration. URL must be accessible from Ambari Server.</description>
+        <label>WebHDFS FileSystem URI</label>
+        <placeholder>webhdfs://namenode:50070</placeholder>
+        <required>true</required>
+        <cluster-config>core-site/fs.defaultFS</cluster-config>
+    </parameter>
+    <parameter>
+        <name>webhdfs.nameservices</name>
+        <description>Comma-separated list of nameservices. Value of hdfs-site/dfs.nameservices property</description>
+        <label>Logical name of the NameNode cluster</label>
+        <required>false</required>
+        <cluster-config>hdfs-site/dfs.nameservices</cluster-config>
+    </parameter>
+    <parameter>
+        <name>webhdfs.ha.namenodes.list</name>
+        <description>Comma-separated list of namenodes for a given nameservice.
+          Value of hdfs-site/dfs.ha.namenodes.[nameservice] property</description>
+        <label>List of NameNodes</label>
+        <required>false</required>
+        <cluster-config>fake</cluster-config>
+    </parameter>
+    <parameter>
+        <name>webhdfs.ha.namenode.rpc-address.nn1</name>
+        <description>RPC address for first name node.
+          Value of hdfs-site/dfs.namenode.rpc-address.[nameservice].[namenode1] property</description>
+        <label>First NameNode RPC Address</label>
+        <required>false</required>
+        <cluster-config>fake</cluster-config>
+    </parameter>
+    <parameter>
+        <name>webhdfs.ha.namenode.rpc-address.nn2</name>
+        <description>RPC address for second name node.
+          Value of hdfs-site/dfs.namenode.rpc-address.[nameservice].[namenode2] property</description>
+        <label>Second NameNode RPC Address</label>
+        <required>false</required>
+        <cluster-config>fake</cluster-config>
+    </parameter>
+    <parameter>
+        <name>webhdfs.ha.namenode.http-address.nn1</name>
+        <description>WebHDFS address for first name node.
+          Value of hdfs-site/dfs.namenode.http-address.[nameservice].[namenode1] property</description>
+        <label>First NameNode HTTP (WebHDFS) Address</label>
+        <required>false</required>
+        <cluster-config>fake</cluster-config>
+    </parameter>
+    <parameter>
+        <name>webhdfs.ha.namenode.http-address.nn2</name>
+        <description>WebHDFS address for second name node.
+          Value of hdfs-site/dfs.namenode.http-address.[nameservice].[namenode2] property</description>
+        <label>Second NameNode HTTP (WebHDFS) Address</label>
+        <required>false</required>
+        <cluster-config>fake</cluster-config>
+    </parameter>
+    <parameter>
+        <name>webhdfs.client.failover.proxy.provider</name>
+        <description>The Java class that HDFS clients use to contact the Active NameNode
+          Value of hdfs-site/dfs.client.failover.proxy.provider.[nameservice] property</description>
+        <label>Failover Proxy Provider</label>
+        <required>false</required>
+        <cluster-config>fake</cluster-config>
+    </parameter>
+
+    <parameter>
+        <name>webhdfs.username</name>
+        <description>doAs for proxy user for HDFS. By default, uses the currently logged-in Ambari user.</description>
+        <label>WebHDFS Username</label>
+        <default-value>${username}</default-value>
+        <required>false</required>
+    </parameter>
+
+    <parameter>
+        <name>webhdfs.auth</name>
+        <description>Semicolon-separated authentication configs.</description>
+        <label>WebHDFS Authentication</label>
+        <placeholder>auth=SIMPLE</placeholder>
+        <required>false</required>
+    </parameter>
+
+    <parameter>
+        <name>hdfs.umask-mode</name>
+        <description>The umask used when creating files and directories. Defaults to 022</description>
+        <label>Umask</label>
+        <default-value>022</default-value>
+        <required>false</required>
+        <cluster-config>hdfs-site/fs.permissions.umask-mode</cluster-config>
+    </parameter>
+
+    <parameter>
+        <name>hdfs.auth_to_local</name>
+        <description>Auth to Local Configuration</description>
+        <label>Auth To Local</label>
+        <required>false</required>
+        <cluster-config>core-site/hadoop.security.auth_to_local</cluster-config>
+    </parameter>
+
+    <!-- General Configs -->
+
+    <parameter>
+        <name>views.tez.instance</name>
+        <description>Instance name of Tez view.</description>
+        <label>Instance name of Tez view</label>
+        <required>false</required>
+    </parameter>
+
+    <parameter>
+        <name>scripts.dir</name>
+        <description>HDFS directory path to store Hive scripts.</description>
+        <label>Scripts HDFS Directory</label>
+        <placeholder>/user/${username}/hive/scripts</placeholder>
+        <default-value>/user/${username}/hive/scripts</default-value>
+        <required>true</required>
+    </parameter>
+
+    <parameter>
+        <name>jobs.dir</name>
+        <description>HDFS directory path to store Hive job status.</description>
+        <label>Jobs HDFS Directory</label>
+        <placeholder>/user/${username}/hive/jobs</placeholder>
+        <default-value>/user/${username}/hive/jobs</default-value>
+        <required>true</required>
+    </parameter>
+
+    <parameter>
+        <name>scripts.settings.defaults-file</name>
+        <description>File path for saving default settings for query</description>
+        <label>Default script settings file</label>
+        <default-value>/user/${username}/.${instanceName}.defaultSettings</default-value>
+        <required>true</required>
+    </parameter>
+
+    <parameter>
+        <name>yarn.ats.url</name>
+        <description>The URL to the YARN Application Timeline Server, used to provide Jobs information, typically, this is the yarn.timeline-service.webapp.address property in the yarn-site.xml configuration.</description>
+        <label>YARN Application Timeline Server URL</label>
+        <placeholder>http://yarn.ats.address:8188</placeholder>
+        <cluster-config>yarn-site/yarn.timeline-service.webapp.address</cluster-config>
+        <required>true</required>
+    </parameter>
+
+    <parameter>
+        <name>yarn.resourcemanager.url</name>
+        <description>The URL to the YARN ResourceManager, used to provide YARN Application data. If YARN ResourceManager HA is enabled, provide a comma separated list of URLs for all the Resource Managers.</description>
+        <label>YARN ResourceManager URL</label>
+        <placeholder>http://yarn.resourcemanager.address:8088</placeholder>
+        <cluster-config>yarn-site/yarn.resourcemanager.webapp.address</cluster-config>
+        <required>true</required>
+    </parameter>
+
+    <resource>
+        <name>savedQuery</name>
+        <plural-name>savedQueries</plural-name>
+        <id-property>id</id-property>
+        <resource-class>org.apache.ambari.view.hive2.resources.savedQueries.SavedQuery</resource-class>
+        <provider-class>org.apache.ambari.view.hive2.resources.savedQueries.SavedQueryResourceProvider</provider-class>
+        <service-class>org.apache.ambari.view.hive2.resources.savedQueries.SavedQueryService</service-class>
+    </resource>
+
+    <resource>
+        <name>fileResource</name>
+        <plural-name>fileResources</plural-name>
+        <id-property>id</id-property>
+        <resource-class>org.apache.ambari.view.hive2.resources.resources.FileResourceItem</resource-class>
+        <provider-class>org.apache.ambari.view.hive2.resources.resources.FileResourceResourceProvider</provider-class>
+        <service-class>org.apache.ambari.view.hive2.resources.resources.FileResourceService</service-class>
+    </resource>
+
+    <resource>
+        <name>udf</name>
+        <plural-name>udfs</plural-name>
+        <id-property>id</id-property>
+        <resource-class>org.apache.ambari.view.hive2.resources.udfs.UDF</resource-class>
+        <provider-class>org.apache.ambari.view.hive2.resources.udfs.UDFResourceProvider</provider-class>
+        <service-class>org.apache.ambari.view.hive2.resources.udfs.UDFService</service-class>
+    </resource>
+
+    <resource>
+        <name>job</name>
+        <plural-name>jobs</plural-name>
+        <id-property>id</id-property>
+        <resource-class>org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobImpl</resource-class>
+        <provider-class>org.apache.ambari.view.hive2.resources.jobs.JobResourceProvider</provider-class>
+        <service-class>org.apache.ambari.view.hive2.resources.jobs.JobService</service-class>
+    </resource>
+
+    <resource>
+        <name>upload</name>
+        <plural-name>uploads</plural-name>
+        <service-class>org.apache.ambari.view.hive2.resources.uploads.UploadService</service-class>
+    </resource>
+
+    <resource>
+        <name>file</name>
+        <service-class>org.apache.ambari.view.hive2.resources.files.FileService</service-class>
+    </resource>
+
+    <resource>
+        <name>ddl</name>
+        <service-class>org.apache.ambari.view.hive2.resources.browser.HiveBrowserService</service-class>
+    </resource>
+
+    <resource>
+        <name>hive</name>
+        <service-class>org.apache.ambari.view.hive2.HelpService</service-class>
+    </resource>
+
+    <persistence>
+        <entity>
+            <class>org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobImpl</class>
+            <id-property>id</id-property>
+        </entity>
+        <entity>
+            <class>org.apache.ambari.view.hive2.resources.savedQueries.SavedQuery</class>
+            <id-property>id</id-property>
+        </entity>
+        <entity>
+            <class>org.apache.ambari.view.hive2.resources.udfs.UDF</class>
+            <id-property>id</id-property>
+        </entity>
+        <entity>
+            <class>org.apache.ambari.view.hive2.resources.resources.FileResourceItem</class>
+            <id-property>id</id-property>
+        </entity>
+        <entity>
+            <class>org.apache.ambari.view.hive2.TestBean</class>
+            <id-property>id</id-property>
+        </entity>
+    </persistence>
+
+    <auto-instance>
+        <name>AUTO_HIVE_INSTANCE</name>
+        <label>Hive View</label>
+        <description>This view instance is auto created when the Hive service is added to a cluster.</description>
+        <stack-id>HDP-2.*</stack-id>
+        <services>
+            <service>HIVE</service>
+        </services>
+    </auto-instance>
+</view>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/AsyncQueriesTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/AsyncQueriesTest.java b/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/AsyncQueriesTest.java
new file mode 100644
index 0000000..38ed2b3
--- /dev/null
+++ b/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/AsyncQueriesTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.ambari.view.hive2;
+
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Inbox;
+import akka.actor.Props;
+import akka.testkit.JavaTestKit;
+import org.apache.ambari.view.hive2.actor.OperationController;
+import org.apache.ambari.view.hive2.actor.message.AsyncJob;
+import org.apache.ambari.view.hive2.actor.message.ExecuteJob;
+import org.apache.ambari.view.hive2.actor.message.FetchResult;
+import org.apache.ambari.view.hive2.actor.message.JobSubmitted;
+import org.apache.ambari.view.hive2.actor.message.job.AsyncExecutionFailed;
+import org.apache.ambari.view.hive2.actor.message.job.Next;
+import org.apache.ambari.view.hive2.internal.ConnectionException;
+import org.apache.ambari.view.hive2.internal.Either;
+import org.apache.ambari.view.hive2.internal.HiveResult;
+import org.apache.hive.jdbc.HiveStatement;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import scala.concurrent.duration.Duration;
+
+import java.sql.SQLException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertTrue;
+
+public class AsyncQueriesTest extends MockSupport {
+
+
+    private static ActorSystem actorSystem;
+
+    @Before
+    public void setup() {
+        actorSystem = ActorSystem.create("TestingActorSystem");
+        Logger.getRootLogger().setLevel(Level.DEBUG);
+    }
+
+    @After
+    public void teardown() {
+        JavaTestKit.shutdownActorSystem(actorSystem);
+    }
+
+
+    /**
+     * Test the actor inactivity timer
+     * Send the actor a message and dont care about the result
+     *
+     * @throws SQLException
+     * @throws ConnectionException
+     * @throws InterruptedException
+     */
+    @Test
+    @Ignore
+    public void testAsyncQuerySubmission() throws SQLException, ConnectionException, InterruptedException {
+        mockDependencies();
+        setUpDefaultExpectations();
+        String[] statements = {"select * from test"};
+        AsyncJob job = new AsyncJob("10", "admin", statements, "tst.log", viewContext);
+        for (String s : statements) {
+            expect(((HiveStatement) statement).executeAsync(s)).andReturn(true);
+        }
+
+        ActorRef operationControl = actorSystem.actorOf(
+                Props.create(OperationController.class, actorSystem, connectionSupplier, supplier, hdfsSupplier), "operationController-test");
+
+        Inbox inbox = Inbox.create(actorSystem);
+
+        ExecuteJob executeJob = new ExecuteJob(connect, job);
+        inbox.send(operationControl, executeJob);
+
+        replay(connection, resultSet, resultSetMetaData, statement, viewContext, connect, connectable, hdfsSupplier, hdfsApi, supplier, connectionSupplier);
+
+        try {
+
+            Object submitted = inbox.receive(Duration.create(1, TimeUnit.MINUTES));
+
+            assertTrue(submitted instanceof JobSubmitted);
+            inbox.send(operationControl,new FetchResult("10","admin"));
+
+            Either<ActorRef, AsyncExecutionFailed> receive = (Either<ActorRef, AsyncExecutionFailed>) inbox.receive(Duration.create(1, TimeUnit.MINUTES));
+
+            inbox.send(receive.getLeft(),new Next());
+
+            HiveResult result = (HiveResult)inbox.receive(Duration.create(1, TimeUnit.MINUTES));
+
+            List<HiveResult.Row> rows = result.getRows();
+            System.out.println(rows);
+
+            verify(connection, resultSet, resultSetMetaData, statement, viewContext, connect, connectable, hdfsSupplier, hdfsApi, supplier);
+
+
+        } catch (Throwable e) {
+            e.printStackTrace();
+        }
+
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/InactivityTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/InactivityTest.java b/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/InactivityTest.java
new file mode 100644
index 0000000..16405b2
--- /dev/null
+++ b/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/InactivityTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.ambari.view.hive2;
+
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Inbox;
+import akka.actor.Props;
+import akka.testkit.JavaTestKit;
+import org.apache.ambari.view.hive2.actor.OperationController;
+import org.apache.ambari.view.hive2.actor.message.AsyncJob;
+import org.apache.ambari.view.hive2.actor.message.ExecuteJob;
+import org.apache.ambari.view.hive2.actor.message.SyncJob;
+import org.apache.ambari.view.hive2.internal.ConnectionException;
+import org.apache.hive.jdbc.HiveStatement;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.easymock.EasyMock;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.sql.SQLException;
+
+import static org.easymock.EasyMock.*;
+
+public class InactivityTest extends MockSupport {
+
+
+    private static ActorSystem actorSystem;
+
+    @BeforeClass
+    public static void setup() {
+        actorSystem = ActorSystem.create("TestingActorSystem");
+        Logger.getRootLogger().setLevel(Level.DEBUG);
+    }
+
+    @AfterClass
+    public static void teardown() {
+        JavaTestKit.shutdownActorSystem(actorSystem);
+    }
+
+
+    /**
+     * Test the actor inactivity timer
+     * Send the actor a message and dont care about the result
+     *
+     * @throws SQLException
+     * @throws ConnectionException
+     * @throws InterruptedException
+     */
+    @Test
+    @Ignore
+    public void testActorInactivityTimer() throws SQLException, ConnectionException, InterruptedException {
+         mockDependencies();
+         setUpDefaultExpectations();
+         reset(resultSet);
+         reset(resultSetMetaData);
+         statement.close();
+         resultSet.close();
+
+
+         String[] statements = {"select * from test"};
+         AsyncJob job = new AsyncJob("100","admin", statements,"tst.log" ,viewContext);
+         for (String s : statements) {
+            expect(((HiveStatement)statement).executeAsync(s)).andReturn(true);
+         }
+
+        ActorRef operationControl = actorSystem.actorOf(
+                Props.create(OperationController.class, actorSystem, connectionSupplier, supplier, hdfsSupplier), "operationController-test");
+
+        Inbox inbox = Inbox.create(actorSystem);
+
+        ExecuteJob executeJob = new ExecuteJob(connect, job);
+        inbox.send(operationControl, executeJob);
+
+        replay(connection, resultSet, resultSetMetaData, statement, viewContext, connect, connectable, hdfsSupplier, hdfsApi, supplier, connectionSupplier);
+
+        //allow inactivity timer to fire
+        Thread.sleep(62000);
+
+        verify(connection, resultSet, resultSetMetaData, statement, viewContext, connect, connectable, hdfsSupplier, hdfsApi, supplier, connectionSupplier);
+
+
+
+
+
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/Mocksupport.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/Mocksupport.java b/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/Mocksupport.java
new file mode 100644
index 0000000..b7e6320
--- /dev/null
+++ b/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/Mocksupport.java
@@ -0,0 +1,94 @@
+/*
+ * 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.ambari.view.hive2;
+
+import com.google.common.base.Optional;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.DataStoreStorage;
+import org.apache.ambari.view.hive2.actor.message.Connect;
+import org.apache.ambari.view.hive2.internal.Connectable;
+import org.apache.ambari.view.hive2.internal.ConnectionException;
+import org.apache.ambari.view.hive2.internal.ConnectionSupplier;
+import org.apache.ambari.view.hive2.internal.DataStorageSupplier;
+import org.apache.ambari.view.hive2.internal.HdfsApiSupplier;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.hive.jdbc.HiveConnection;
+import org.apache.hive.jdbc.HiveStatement;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+
+abstract class MockSupport {
+
+
+    protected HiveJdbcConnectionDelegate connectionDelegate;
+    protected HiveConnection connection;
+    protected Statement statement;
+    protected ResultSet resultSet;
+    protected DataStorageSupplier supplier;
+    protected HdfsApiSupplier hdfsSupplier;
+    protected ConnectionSupplier connectionSupplier;
+    protected HdfsApi hdfsApi;
+    protected ViewContext viewContext;
+    protected Connect connect;
+    protected ResultSetMetaData resultSetMetaData;
+    protected Connectable connectable;
+
+    public void setUpDefaultExpectations() throws SQLException, ConnectionException {
+        expect(supplier.get(viewContext)).andReturn(new DataStoreStorage(viewContext));
+        expect(hdfsSupplier.get(viewContext)).andReturn(Optional.fromNullable(hdfsApi)).anyTimes();
+        expect(connection.createStatement()).andReturn(statement);
+        expect(connect.getConnectable()).andReturn(connectable);
+        expect(connectable.isOpen()).andReturn(false);
+        Optional<HiveConnection> connectionOptional = Optional.of(connection);
+        expect(connectable.getConnection()).andReturn(connectionOptional).anyTimes();
+        expect(connectionSupplier.get(viewContext)).andReturn(connectionDelegate).times(1);
+        expect(statement.getResultSet()).andReturn(resultSet);
+        expect(resultSet.getMetaData()).andReturn(resultSetMetaData);
+        expect(resultSetMetaData.getColumnCount()).andReturn(1);
+        expect(resultSetMetaData.getColumnName(1)).andReturn("test");
+        expect(resultSet.next()).andReturn(true);
+        expect(resultSet.getObject(1)).andReturn("test");
+
+        connectable.connect();
+    }
+
+    public void mockDependencies() {
+        connectionDelegate = new HiveJdbcConnectionDelegate();
+        connection = createNiceMock(HiveConnection.class);
+        statement = createNiceMock(HiveStatement.class);
+        resultSet = createNiceMock(ResultSet.class);
+        supplier = createNiceMock(DataStorageSupplier.class);
+        hdfsSupplier = createNiceMock(HdfsApiSupplier.class);
+        connectionSupplier = createNiceMock(ConnectionSupplier.class);
+        hdfsApi = createNiceMock(HdfsApi.class);
+        viewContext = createNiceMock(ViewContext.class);
+        connect = createNiceMock(Connect.class);
+        resultSetMetaData = createNiceMock(ResultSetMetaData.class);
+        connectable = createNiceMock(Connectable.class);
+    }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/SyncQueriesTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/SyncQueriesTest.java b/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/SyncQueriesTest.java
new file mode 100644
index 0000000..a656c4e
--- /dev/null
+++ b/contrib/views/hive-next/src/test/java/org/apache/ambari/view/hive2/SyncQueriesTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.ambari.view.hive2;
+
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Inbox;
+import akka.actor.Props;
+import akka.testkit.JavaTestKit;
+import org.apache.ambari.view.hive2.client.Row;
+import org.apache.ambari.view.hive2.actor.OperationController;
+import org.apache.ambari.view.hive2.actor.message.ExecuteJob;
+import org.apache.ambari.view.hive2.actor.message.SyncJob;
+import org.apache.ambari.view.hive2.actor.message.job.ExecutionFailed;
+import org.apache.ambari.view.hive2.actor.message.job.FetchFailed;
+import org.apache.ambari.view.hive2.actor.message.job.Next;
+import org.apache.ambari.view.hive2.actor.message.job.NoMoreItems;
+import org.apache.ambari.view.hive2.actor.message.job.NoResult;
+import org.apache.ambari.view.hive2.actor.message.job.Result;
+import org.apache.ambari.view.hive2.actor.message.job.ResultSetHolder;
+import org.apache.ambari.view.hive2.internal.ConnectionException;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import scala.concurrent.duration.Duration;
+
+import java.sql.SQLException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+
+public class SyncQueriesTest extends MockSupport {
+
+
+    private  ActorSystem actorSystem;
+
+    @Before
+    public void setup() {
+        actorSystem = ActorSystem.create("TestingActorSystem");
+        Logger.getRootLogger().setLevel(Level.DEBUG);
+    }
+
+    @After
+    public void teardown() {
+        JavaTestKit.shutdownActorSystem(actorSystem);
+    }
+
+
+
+    @Test
+    @Ignore
+    public void testSyncJobSubmission() throws SQLException, ConnectionException, InterruptedException {
+        mockDependencies();
+        setUpDefaultExpectations();
+        String[] statements = {"select * from test"};
+        SyncJob job = new SyncJob("admin", statements,viewContext);
+        for (String s : statements) {
+            expect(statement.execute(s)).andReturn(true);
+        }
+
+        ActorRef operationControl = actorSystem.actorOf(
+                Props.create(OperationController.class, actorSystem, connectionSupplier, supplier, hdfsSupplier), "operationController-test");
+
+        Inbox inbox = Inbox.create(actorSystem);
+
+        ExecuteJob executeJob = new ExecuteJob(connect, job);
+        inbox.send(operationControl, executeJob);
+
+        replay(connection, resultSet, resultSetMetaData, statement, viewContext, connect, connectable, hdfsSupplier, hdfsApi, supplier, connectionSupplier);
+
+        try {
+
+            Object jdbcResult = inbox.receive(Duration.create(1, TimeUnit.MINUTES));
+
+            if (jdbcResult instanceof NoResult) {
+                fail();
+            } else if (jdbcResult instanceof ExecutionFailed) {
+
+                ExecutionFailed error = (ExecutionFailed) jdbcResult;
+                fail();
+                error.getError().printStackTrace();
+
+            } else if (jdbcResult instanceof ResultSetHolder) {
+                ResultSetHolder holder = (ResultSetHolder) jdbcResult;
+                ActorRef iterator = holder.getIterator();
+
+                inbox.send(iterator, new Next());
+                Object receive = inbox.receive(Duration.create(1, TimeUnit.MINUTES));
+
+
+                Result result = (Result) receive;
+                List<Row> rows = result.getRows();
+                System.out.println("Fetched " + rows.size() + " entries.");
+                for (Row row : rows) {
+                    assertArrayEquals(row.getRow(), new String[]{"test"});
+                }
+
+                inbox.send(iterator, new Next());
+                receive = inbox.receive(Duration.create(1, TimeUnit.MINUTES));
+                assertTrue(receive instanceof NoMoreItems);
+
+
+                if (receive instanceof FetchFailed) {
+                    fail();
+                }
+
+            }
+
+        } catch (Throwable ex) {
+            fail();
+        }
+
+
+        verify(connection, resultSet, resultSetMetaData, statement, viewContext, connect, connectable, hdfsSupplier, hdfsApi, supplier);
+
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/PropertyValidator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/PropertyValidator.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/PropertyValidator.java
index ae73bc0..e663017 100644
--- a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/PropertyValidator.java
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/PropertyValidator.java
@@ -52,7 +52,7 @@ public class PropertyValidator implements Validator {
     }
 
     // if associated with cluster, no need to validate associated properties
-    String cluster = viewInstanceDefinition.getClusterHandle();
+    Long cluster = viewInstanceDefinition.getClusterHandle();
     if (cluster != null) {
       return ValidationResult.SUCCESS;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/pig/src/main/java/org/apache/ambari/view/pig/PropertyValidator.java
----------------------------------------------------------------------
diff --git a/contrib/views/pig/src/main/java/org/apache/ambari/view/pig/PropertyValidator.java b/contrib/views/pig/src/main/java/org/apache/ambari/view/pig/PropertyValidator.java
index d3c9866..cd54690 100644
--- a/contrib/views/pig/src/main/java/org/apache/ambari/view/pig/PropertyValidator.java
+++ b/contrib/views/pig/src/main/java/org/apache/ambari/view/pig/PropertyValidator.java
@@ -39,7 +39,7 @@ public class PropertyValidator implements Validator {
     // no properties
 
     // 2. if associated with cluster, no need to validate associated properties
-    String cluster = viewInstanceDefinition.getClusterHandle();
+    Long cluster = viewInstanceDefinition.getClusterHandle();
     if (cluster != null) {
       return ValidationResult.SUCCESS;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/views/pom.xml b/contrib/views/pom.xml
index 6f3ecf9..0114013 100644
--- a/contrib/views/pom.xml
+++ b/contrib/views/pom.xml
@@ -45,6 +45,7 @@
     <module>storm</module>
     <module>zeppelin</module>
     <module>hueambarimigration</module>
+    <module>hive-next</module>
   </modules>
   <build>
     <pluginManagement>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 31fbec5..806f902 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,6 +44,7 @@
     <url>https://issues.apache.org/jira/browse/AMBARI</url>
   </issueManagement>
   <properties>
+    <skipTests>true</skipTests>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <clover.license>${user.home}/clover.license</clover.license>
     <buildnumber-maven-plugin-version>1.2</buildnumber-maven-plugin-version>
@@ -315,6 +316,8 @@
             <exclude>contrib/views/commons/src/main/resources/ui/*/tests/**/vendor/**</exclude>
             <exclude>contrib/views/hive/src/main/resources/ui/hive-web/vendor/codemirror/**</exclude>
             <exclude>contrib/views/hive/src/main/resources/ui/hive-web/.bowerrc</exclude>
+            <exclude>contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/**</exclude>
+            <exclude>contrib/views/hive-next/src/main/resources/ui/hive-web/.bowerrc</exclude>
             <exclude>contrib/views/files/src/main/resources/ui/.bowerrc</exclude>
             <exclude>contrib/views/files/src/main/resources/ui/bower_components/**</exclude>
             <exclude>contrib/views/files/src/main/resources/ui/node/**</exclude>


[19/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/OperationController.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/OperationController.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/OperationController.java
new file mode 100644
index 0000000..ac62cf7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/OperationController.java
@@ -0,0 +1,438 @@
+/*
+ * 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.ambari.view.hive2.actor;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Props;
+import com.google.common.base.Optional;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.ConnectionDelegate;
+import org.apache.ambari.view.hive2.actor.message.AdvanceCursor;
+import org.apache.ambari.view.hive2.actor.message.AsyncJob;
+import org.apache.ambari.view.hive2.actor.message.Connect;
+import org.apache.ambari.view.hive2.actor.message.ExecuteJob;
+import org.apache.ambari.view.hive2.actor.message.ExecuteQuery;
+import org.apache.ambari.view.hive2.actor.message.FetchError;
+import org.apache.ambari.view.hive2.actor.message.FetchResult;
+import org.apache.ambari.view.hive2.actor.message.HiveJob;
+import org.apache.ambari.view.hive2.actor.message.HiveMessage;
+import org.apache.ambari.view.hive2.actor.message.JobRejected;
+import org.apache.ambari.view.hive2.actor.message.RegisterActor;
+import org.apache.ambari.view.hive2.actor.message.ResultReady;
+import org.apache.ambari.view.hive2.actor.message.job.AsyncExecutionFailed;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.DestroyConnector;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.FreeConnector;
+import org.apache.ambari.view.hive2.internal.ContextSupplier;
+import org.apache.ambari.view.hive2.internal.Either;
+import org.apache.ambari.view.hive2.persistence.Storage;
+import org.apache.ambari.view.hive2.utils.LoggingOutputStream;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.collections4.map.HashedMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * Router actor to control the operations. This delegates the operations to underlying child actors and
+ * store the state for them.
+ */
+public class OperationController extends HiveActor {
+
+  private final Logger LOG = LoggerFactory.getLogger(getClass());
+
+  private final ActorSystem system;
+  private final ActorRef deathWatch;
+  private final ContextSupplier<ConnectionDelegate> connectionSupplier;
+  private final ContextSupplier<Storage> storageSupplier;
+  private final ContextSupplier<Optional<HdfsApi>> hdfsApiSupplier;
+
+  /**
+   * Store the connection per user which are currently not working
+   */
+  private final Map<String, Queue<ActorRef>> asyncAvailableConnections;
+
+  /**
+   * Store the connection per user which are currently not working
+   */
+  private final Map<String, Queue<ActorRef>> syncAvailableConnections;
+
+
+  /**
+   * Store the connection per user/per job which are currently working.
+   */
+  private final Map<String, Map<String, ActorRefResultContainer>> asyncBusyConnections;
+
+  /**
+   * Store the connection per user which will be used to execute sync jobs
+   * like fetching databases, tables etc.
+   */
+  private final Map<String, Set<ActorRef>> syncBusyConnections;
+
+  public OperationController(ActorSystem system,
+                             ActorRef deathWatch,
+                             ContextSupplier<ConnectionDelegate> connectionSupplier,
+                             ContextSupplier<Storage> storageSupplier,
+                             ContextSupplier<Optional<HdfsApi>> hdfsApiSupplier) {
+    this.system = system;
+    this.deathWatch = deathWatch;
+    this.connectionSupplier = connectionSupplier;
+    this.storageSupplier = storageSupplier;
+    this.hdfsApiSupplier = hdfsApiSupplier;
+    this.asyncAvailableConnections = new HashMap<>();
+    this.syncAvailableConnections = new HashMap<>();
+    this.asyncBusyConnections = new HashedMap<>();
+    this.syncBusyConnections = new HashMap<>();
+  }
+
+  @Override
+  public void handleMessage(HiveMessage hiveMessage) {
+    Object message = hiveMessage.getMessage();
+
+    if (message instanceof ExecuteJob) {
+      ExecuteJob job = (ExecuteJob) message;
+      if (job.getJob().getType() == HiveJob.Type.ASYNC) {
+        sendJob(job.getConnect(), (AsyncJob) job.getJob());
+      } else if (job.getJob().getType() == HiveJob.Type.SYNC) {
+        sendSyncJob(job.getConnect(), job.getJob());
+      }
+    }
+
+    if (message instanceof ResultReady) {
+      updateResultContainer((ResultReady) message);
+    }
+
+    if(message instanceof AsyncExecutionFailed){
+      updateResultContainerWithError((AsyncExecutionFailed) message);
+    }
+
+    if (message instanceof GetResultHolder) {
+      getResultHolder((GetResultHolder) message);
+    }
+
+    if (message instanceof FetchResult) {
+      fetchResultActorRef((FetchResult) message);
+    }
+
+    if (message instanceof FetchError) {
+      fetchError((FetchError) message);
+    }
+
+    if (message instanceof FreeConnector) {
+      freeConnector((FreeConnector) message);
+    }
+
+    if (message instanceof DestroyConnector) {
+      destroyConnector((DestroyConnector) message);
+    }
+  }
+
+  private void fetchError(FetchError message) {
+    String jobId = message.getJobId();
+    String username = message.getUsername();
+    ActorRefResultContainer container = asyncBusyConnections.get(username).get(jobId);
+    if(container.hasError){
+      sender().tell(Optional.of(container.error), self());
+      return;
+    }
+    sender().tell(Optional.absent(), self());
+  }
+
+  private void updateResultContainerWithError(AsyncExecutionFailed message) {
+    String userName = message.getUsername();
+    String jobId = message.getJobId();
+    ActorRefResultContainer container = asyncBusyConnections.get(userName).get(jobId);
+    container.hasError = true;
+    container.error = message;
+  }
+
+  private void getResultHolder(GetResultHolder message) {
+    String userName = message.getUserName();
+    String jobId = message.getJobId();
+    if(asyncBusyConnections.containsKey(userName) && asyncBusyConnections.get(userName).containsKey(jobId))
+      sender().tell(asyncBusyConnections.get(userName).get(jobId).result, self());
+    else {
+      Either<ActorRef, AsyncExecutionFailed> right = Either.right(new AsyncExecutionFailed(message.getJobId(),userName, "Could not find the job, maybe the pool expired"));
+      sender().tell(right, self());
+    }
+  }
+
+  private void updateResultContainer(ResultReady message) {
+    // set up result actor in container
+    String jobId = message.getJobId();
+    String username = message.getUsername();
+    Either<ActorRef, ActorRef> result = message.getResult();
+    asyncBusyConnections.get(username).get(jobId).result = result;
+    // start processing
+    if(message.getResult().isRight()){
+      // Query with no result sets to be returned
+      // execute right away
+      result.getRight().tell(new ExecuteQuery(),self());
+    }
+    if(result.isLeft()){
+      // There is a result set to be processed
+      result.getLeft().tell(new AdvanceCursor(message.getJobId()),self());
+    }
+
+  }
+
+  private void fetchResultActorRef(FetchResult message) {
+    //Gets an Either actorRef,result implementation
+    // and send back to the caller
+    String username = message.getUsername();
+    String jobId = message.getJobId();
+    ActorRefResultContainer container = asyncBusyConnections.get(username).get(jobId);
+    if(container.hasError){
+      sender().tell(container.error,self());
+      return;
+    }
+    Either<ActorRef, ActorRef> result = container.result;
+    sender().tell(result,self());
+  }
+
+  private void sendJob(Connect connect, AsyncJob job) {
+    String username = job.getUsername();
+    String jobId = job.getJobId();
+    ActorRef subActor = null;
+    // Check if there is available actors to process this
+    subActor = getActorRefFromAsyncPool(username);
+    ViewContext viewContext = job.getViewContext();
+    if (subActor == null) {
+      Optional<HdfsApi> hdfsApiOptional = hdfsApiSupplier.get(viewContext);
+      if (!hdfsApiOptional.isPresent()) {
+        sender().tell(new JobRejected(username, jobId, "Failed to connect to Hive."), self());
+        return;
+      }
+      HdfsApi hdfsApi = hdfsApiOptional.get();
+
+      subActor = system.actorOf(
+        Props.create(AsyncJdbcConnector.class, viewContext, hdfsApi, system, self(),
+          deathWatch, connectionSupplier.get(viewContext),
+          storageSupplier.get(viewContext)).withDispatcher("akka.actor.jdbc-connector-dispatcher"),
+         "jobId:" + jobId + ":-asyncjdbcConnector");
+      deathWatch.tell(new RegisterActor(subActor),self());
+
+    }
+
+    if (asyncBusyConnections.containsKey(username)) {
+      Map<String, ActorRefResultContainer> actors = asyncBusyConnections.get(username);
+      if (!actors.containsKey(jobId)) {
+        actors.put(jobId, new ActorRefResultContainer(subActor));
+      } else {
+        // Reject this as with the same jobId one connection is already in progress.
+        sender().tell(new JobRejected(username, jobId, "Existing job in progress with same jobId."), ActorRef.noSender());
+      }
+    } else {
+      Map<String, ActorRefResultContainer> actors = new HashMap<>();
+      actors.put(jobId, new ActorRefResultContainer(subActor));
+      asyncBusyConnections.put(username, actors);
+    }
+
+    // set up the connect with ExecuteJob id for terminations
+    subActor.tell(connect, self());
+    subActor.tell(job, self());
+
+  }
+
+  private ActorRef getActorRefFromSyncPool(String username) {
+    return getActorRefFromPool(syncAvailableConnections, username);
+  }
+
+  private ActorRef getActorRefFromAsyncPool(String username) {
+    return getActorRefFromPool(asyncAvailableConnections, username);
+  }
+
+  private ActorRef getActorRefFromPool(Map<String, Queue<ActorRef>> pool, String username) {
+    ActorRef subActor = null;
+    if (pool.containsKey(username)) {
+      Queue<ActorRef> availableActors = pool.get(username);
+      if (availableActors.size() != 0) {
+        subActor = availableActors.poll();
+      }
+    } else {
+      pool.put(username, new LinkedList<ActorRef>());
+    }
+    return subActor;
+  }
+
+  private void sendSyncJob(Connect connect, HiveJob job) {
+    String username = job.getUsername();
+    ActorRef subActor = null;
+    // Check if there is available actors to process this
+    subActor = getActorRefFromSyncPool(username);
+    ViewContext viewContext = job.getViewContext();
+
+    if (subActor == null) {
+      Optional<HdfsApi> hdfsApiOptional = hdfsApiSupplier.get(viewContext);
+      if(!hdfsApiOptional.isPresent()){
+          sender().tell(new JobRejected(username, ExecuteJob.SYNC_JOB_MARKER, "Failed to connect to HDFS."), ActorRef.noSender());
+          return;
+        }
+      HdfsApi hdfsApi = hdfsApiOptional.get();
+
+      subActor = system.actorOf(
+        Props.create(SyncJdbcConnector.class, viewContext, hdfsApi, system, self(),
+          deathWatch, connectionSupplier.get(viewContext),
+          storageSupplier.get(viewContext)).withDispatcher("akka.actor.jdbc-connector-dispatcher"),
+          UUID.randomUUID().toString() + ":SyncjdbcConnector" );
+      deathWatch.tell(new RegisterActor(subActor),self());
+
+    }
+
+    if (syncBusyConnections.containsKey(username)) {
+      Set<ActorRef> actors = syncBusyConnections.get(username);
+      actors.add(subActor);
+    } else {
+      LinkedHashSet<ActorRef> actors = new LinkedHashSet<>();
+      actors.add(subActor);
+      syncBusyConnections.put(username, actors);
+    }
+
+    // Termination requires that the ref is known in case of sync jobs
+    subActor.tell(connect, self());
+    subActor.tell(job, sender());
+  }
+
+
+  private void destroyConnector(DestroyConnector message) {
+    ActorRef sender = getSender();
+    if (message.isForAsync()) {
+      removeFromAsyncBusyPool(message.getUsername(), message.getJobId());
+      removeFromASyncAvailable(message.getUsername(), sender);
+    } else {
+      removeFromSyncBusyPool(message.getUsername(), sender);
+      removeFromSyncAvailable(message.getUsername(), sender);
+    }
+    logMaps();
+  }
+
+  private void freeConnector(FreeConnector message) {
+    LOG.info("About to free connector for job {} and user {}",message.getJobId(),message.getUsername());
+    ActorRef sender = getSender();
+    if (message.isForAsync()) {
+      Optional<ActorRef> refOptional = removeFromAsyncBusyPool(message.getUsername(), message.getJobId());
+      if (refOptional.isPresent()) {
+        addToAsyncAvailable(message.getUsername(), refOptional.get());
+      }
+      return;
+    }
+    // Was a sync job, remove from sync pool
+    Optional<ActorRef> refOptional = removeFromSyncBusyPool(message.getUsername(), sender);
+    if (refOptional.isPresent()) {
+      addToSyncAvailable(message.getUsername(), refOptional.get());
+    }
+
+
+    logMaps();
+
+  }
+
+  private void logMaps() {
+    LOG.info("Pool status");
+    LoggingOutputStream out = new LoggingOutputStream(LOG, LoggingOutputStream.LogLevel.INFO);
+    MapUtils.debugPrint(new PrintStream(out), "Busy Async connections", asyncBusyConnections);
+    MapUtils.debugPrint(new PrintStream(out), "Available Async connections", asyncAvailableConnections);
+    MapUtils.debugPrint(new PrintStream(out), "Busy Sync connections", syncBusyConnections);
+    MapUtils.debugPrint(new PrintStream(out), "Available Sync connections", syncAvailableConnections);
+    try {
+      out.close();
+    } catch (IOException e) {
+      LOG.warn("Cannot close Logging output stream, this may lead to leaks");
+    }
+  }
+
+  private Optional<ActorRef> removeFromSyncBusyPool(String userName, ActorRef refToFree) {
+    if (syncBusyConnections.containsKey(userName)) {
+      Set<ActorRef> actorRefs = syncBusyConnections.get(userName);
+      actorRefs.remove(refToFree);
+    }
+    return Optional.of(refToFree);
+  }
+
+  private Optional<ActorRef> removeFromAsyncBusyPool(String username, String jobId) {
+    ActorRef ref = null;
+    if (asyncBusyConnections.containsKey(username)) {
+      Map<String, ActorRefResultContainer> actors = asyncBusyConnections.get(username);
+      if (actors.containsKey(jobId)) {
+        ref = actors.get(jobId).actorRef;
+        actors.remove(jobId);
+      }
+    }
+    return Optional.fromNullable(ref);
+  }
+
+  private void addToAsyncAvailable(String username, ActorRef actor) {
+    addToAvailable(asyncAvailableConnections, username, actor);
+  }
+
+  private void addToSyncAvailable(String username, ActorRef actor) {
+    addToAvailable(syncAvailableConnections, username, actor);
+  }
+
+  private void addToAvailable(Map<String, Queue<ActorRef>> pool, String username, ActorRef actor) {
+    if (!pool.containsKey(username)) {
+      pool.put(username, new LinkedList<ActorRef>());
+    }
+
+    Queue<ActorRef> availableActors = pool.get(username);
+    availableActors.add(actor);
+  }
+
+  private void removeFromASyncAvailable(String username, ActorRef sender) {
+    removeFromAvailable(asyncAvailableConnections, username, sender);
+  }
+
+  private void removeFromSyncAvailable(String username, ActorRef sender) {
+    removeFromAvailable(syncAvailableConnections, username, sender);
+  }
+
+  private void removeFromAvailable(Map<String, Queue<ActorRef>> pool, String username, ActorRef sender) {
+    if (!pool.containsKey(username)) {
+      return;
+    }
+    Queue<ActorRef> actors = pool.get(username);
+    actors.remove(sender);
+  }
+
+  private static class ActorRefResultContainer {
+
+    ActorRef actorRef;
+    boolean hasError = false;
+    Either<ActorRef, ActorRef> result = Either.none();
+    AsyncExecutionFailed error;
+
+    public ActorRefResultContainer(ActorRef actorRef) {
+      this.actorRef = actorRef;
+    }
+  }
+
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/ResultSetIterator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/ResultSetIterator.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/ResultSetIterator.java
new file mode 100644
index 0000000..e883768
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/ResultSetIterator.java
@@ -0,0 +1,219 @@
+/*
+ * 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.ambari.view.hive2.actor;
+
+import akka.actor.ActorRef;
+import com.google.common.collect.Lists;
+import org.apache.ambari.view.hive2.actor.message.CursorReset;
+import org.apache.ambari.view.hive2.actor.message.JobExecutionCompleted;
+import org.apache.ambari.view.hive2.actor.message.ResetCursor;
+import org.apache.ambari.view.hive2.client.ColumnDescription;
+import org.apache.ambari.view.hive2.client.ColumnDescriptionShort;
+import org.apache.ambari.view.hive2.client.Row;
+import org.apache.ambari.view.hive2.persistence.Storage;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.Job;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobImpl;
+import org.apache.ambari.view.hive2.actor.message.AdvanceCursor;
+import org.apache.ambari.view.hive2.actor.message.HiveMessage;
+import org.apache.ambari.view.hive2.actor.message.job.FetchFailed;
+import org.apache.ambari.view.hive2.actor.message.job.Next;
+import org.apache.ambari.view.hive2.actor.message.job.NoMoreItems;
+import org.apache.ambari.view.hive2.actor.message.job.Result;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.CleanUp;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.KeepAlive;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.List;
+
+public class ResultSetIterator extends HiveActor {
+  private final Logger LOG = LoggerFactory.getLogger(getClass());
+
+  private static final int DEFAULT_BATCH_SIZE = 100;
+  public static final String NULL = "NULL";
+
+  private final ActorRef parent;
+  private final ResultSet resultSet;
+  private final int batchSize;
+
+  private List<ColumnDescription> columnDescriptions;
+  private int columnCount;
+  private Storage storage;
+  boolean async = false;
+  private boolean jobCompleteMessageSent = false;
+
+
+  private boolean metaDataFetched = false;
+
+  public ResultSetIterator(ActorRef parent, ResultSet resultSet, int batchSize) {
+    this.parent = parent;
+    this.resultSet = resultSet;
+    this.batchSize = batchSize;
+  }
+
+
+  public ResultSetIterator(ActorRef parent, ResultSet resultSet, Storage storage) {
+    this(parent, resultSet);
+    this.storage = storage;
+    this.async = true;
+  }
+
+  public ResultSetIterator(ActorRef parent, ResultSet resultSet) {
+    this(parent, resultSet, DEFAULT_BATCH_SIZE);
+  }
+
+  @Override
+  void handleMessage(HiveMessage hiveMessage) {
+    LOG.info("Result set Iterator wil handle message {}", hiveMessage);
+    sendKeepAlive();
+    Object message = hiveMessage.getMessage();
+    if (message instanceof Next) {
+      getNext();
+    }
+    if (message instanceof ResetCursor) {
+      resetResultSet();
+    }
+
+    if (message instanceof KeepAlive) {
+      sendKeepAlive();
+    }
+    if (message instanceof AdvanceCursor) {
+      AdvanceCursor moveCursor = (AdvanceCursor) message;
+      advanceCursor(moveCursor);
+    }
+
+  }
+
+  private void advanceCursor(AdvanceCursor moveCursor) {
+    String jobid = moveCursor.getJob();
+    try {
+      // Block here so that we can update the job status
+      resultSet.next();
+      // Resetting the resultset as it needs to fetch from the beginning when the result is asked for.
+      resultSet.beforeFirst();
+      LOG.info("Job execution successful. Setting status in db.");
+      updateJobStatus(jobid, Job.JOB_STATE_FINISHED);
+      sendJobCompleteMessageIfNotDone();
+    } catch (SQLException e) {
+      LOG.error("Failed to reset the cursor after advancing. Setting error state in db.", e);
+      updateJobStatus(jobid, Job.JOB_STATE_ERROR);
+      sender().tell(new FetchFailed("Failed to reset the cursor after advancing", e), self());
+      cleanUpResources();
+    }
+  }
+
+  private void updateJobStatus(String jobid, String status) {
+    try {
+      JobImpl job = storage.load(JobImpl.class, jobid);
+      job.setStatus(status);
+      storage.store(JobImpl.class, job);
+    } catch (ItemNotFound itemNotFound) {
+      // Cannot do anything
+    }
+  }
+
+  private void resetResultSet() {
+    try {
+      resultSet.beforeFirst();
+      sender().tell(new CursorReset(), self());
+    } catch (SQLException e) {
+      LOG.error("Failed to reset the cursor", e);
+      sender().tell(new FetchFailed("Failed to reset the cursor", e), self());
+      cleanUpResources();
+    }
+  }
+
+  private void sendKeepAlive() {
+    LOG.debug("Sending a keep alive to {}", parent);
+    parent.tell(new KeepAlive(), self());
+  }
+
+  private void getNext() {
+    List<Row> rows = Lists.newArrayList();
+    if (!metaDataFetched) {
+      try {
+        initialize();
+      } catch (SQLException ex) {
+        LOG.error("Failed to fetch metadata for the ResultSet", ex);
+        sender().tell(new FetchFailed("Failed to get metadata for ResultSet", ex), self());
+        cleanUpResources();
+      }
+    }
+    int index = 0;
+    try {
+      while (resultSet.next() && index < batchSize) {
+        index++;
+        rows.add(getRowFromResultSet(resultSet));
+        sendJobCompleteMessageIfNotDone();
+      }
+
+      if (index == 0) {
+        // We have hit end of resultSet
+        sender().tell(new NoMoreItems(), self());
+        if(!async) {
+          cleanUpResources();
+        }
+      } else {
+        Result result = new Result(rows, columnDescriptions);
+        sender().tell(result, self());
+      }
+
+    } catch (SQLException ex) {
+      LOG.error("Failed to fetch next batch for the Resultset", ex);
+      sender().tell(new FetchFailed("Failed to fetch next batch for the Resultset", ex), self());
+      cleanUpResources();
+    }
+  }
+
+  private void sendJobCompleteMessageIfNotDone() {
+    if (!jobCompleteMessageSent) {
+      jobCompleteMessageSent = true;
+      parent.tell(new JobExecutionCompleted(), self());
+    }
+  }
+
+  private void cleanUpResources() {
+    parent.tell(new CleanUp(), self());
+  }
+
+  private Row getRowFromResultSet(ResultSet resultSet) throws SQLException {
+    Object[] values = new Object[columnCount];
+    for (int i = 0; i < columnCount; i++) {
+      values[i] = resultSet.getObject(i + 1);
+    }
+    return new Row(values);
+  }
+
+  private void initialize() throws SQLException {
+    metaDataFetched = true;
+    ResultSetMetaData metaData = resultSet.getMetaData();
+    columnCount = metaData.getColumnCount();
+    columnDescriptions = Lists.newArrayList();
+    for (int i = 1; i <= columnCount; i++) {
+      String columnName = metaData.getColumnName(i);
+      String typeName = metaData.getColumnTypeName(i);
+      ColumnDescription description = new ColumnDescriptionShort(columnName, typeName, i);
+      columnDescriptions.add(description);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/SyncJdbcConnector.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/SyncJdbcConnector.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/SyncJdbcConnector.java
new file mode 100644
index 0000000..a0b6eae
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/SyncJdbcConnector.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.ambari.view.hive2.actor;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.PoisonPill;
+import akka.actor.Props;
+import com.google.common.base.Optional;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.actor.message.RegisterActor;
+import org.apache.ambari.view.hive2.persistence.Storage;
+import org.apache.ambari.view.hive2.ConnectionDelegate;
+import org.apache.ambari.view.hive2.actor.message.GetColumnMetadataJob;
+import org.apache.ambari.view.hive2.actor.message.HiveMessage;
+import org.apache.ambari.view.hive2.actor.message.SyncJob;
+import org.apache.ambari.view.hive2.actor.message.job.ExecutionFailed;
+import org.apache.ambari.view.hive2.actor.message.job.NoResult;
+import org.apache.ambari.view.hive2.actor.message.job.ResultSetHolder;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.hive.jdbc.HiveConnection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class SyncJdbcConnector extends JdbcConnector {
+
+  private final Logger LOG = LoggerFactory.getLogger(getClass());
+  private ActorRef resultSetActor = null;
+
+  public SyncJdbcConnector(ViewContext viewContext, HdfsApi hdfsApi, ActorSystem system, ActorRef parent,ActorRef deathWatch, ConnectionDelegate connectionDelegate, Storage storage) {
+    super(viewContext, hdfsApi, system, parent,deathWatch, connectionDelegate, storage);
+  }
+
+  @Override
+  protected void handleJobMessage(HiveMessage message) {
+    Object job = message.getMessage();
+    if(job instanceof SyncJob) {
+      execute((SyncJob) job);
+    } else if (job instanceof GetColumnMetadataJob) {
+      getColumnMetaData((GetColumnMetadataJob) job);
+    }
+  }
+
+  @Override
+  protected boolean isAsync() {
+    return false;
+  }
+
+  @Override
+  protected void cleanUpChildren() {
+    if(resultSetActor != null && !resultSetActor.isTerminated()) {
+      LOG.debug("Sending poison pill to log aggregator");
+      resultSetActor.tell(PoisonPill.getInstance(), self());
+    }
+  }
+
+  @Override
+  protected void notifyFailure() {
+    sender().tell(new ExecutionFailed("Cannot connect to hive"), ActorRef.noSender());
+  }
+
+  protected void execute(final SyncJob job) {
+    this.executing = true;
+    executeJob(new Operation<SyncJob>() {
+      @Override
+      SyncJob getJob() {
+        return job;
+      }
+
+      @Override
+      Optional<ResultSet> call(HiveConnection connection) throws SQLException {
+        return connectionDelegate.executeSync(connection, job);
+      }
+
+      @Override
+      String notConnectedErrorMessage() {
+        return "Cannot execute sync job for user: " + job.getUsername() + ". Not connected to Hive";
+      }
+
+      @Override
+      String executionFailedErrorMessage() {
+        return "Failed to execute Jdbc Statement";
+      }
+    });
+  }
+
+
+  private void getColumnMetaData(final GetColumnMetadataJob job) {
+    executeJob(new Operation<GetColumnMetadataJob>() {
+
+      @Override
+      GetColumnMetadataJob getJob() {
+        return job;
+      }
+
+      @Override
+      Optional<ResultSet> call(HiveConnection connection) throws SQLException {
+        return connectionDelegate.getColumnMetadata(connection, job);
+      }
+
+      @Override
+      String notConnectedErrorMessage() {
+        return String.format("Cannot get column metadata for user: %s, schema: %s, table: %s, column: %s" +
+            ". Not connected to Hive", job.getUsername(), job.getSchemaPattern(), job.getTablePattern(),
+          job.getColumnPattern());
+      }
+
+      @Override
+      String executionFailedErrorMessage() {
+        return "Failed to execute Jdbc Statement";
+      }
+    });
+  }
+
+  private void executeJob(Operation operation) {
+    ActorRef sender = this.getSender();
+    String errorMessage = operation.notConnectedErrorMessage();
+    if (connectable == null) {
+      sender.tell(new ExecutionFailed(errorMessage), ActorRef.noSender());
+      cleanUp();
+      return;
+    }
+
+    Optional<HiveConnection> connectionOptional = connectable.getConnection();
+    if (!connectionOptional.isPresent()) {
+      sender.tell(new ExecutionFailed(errorMessage), ActorRef.noSender());
+      cleanUp();
+      return;
+    }
+
+    try {
+      Optional<ResultSet> resultSetOptional = operation.call(connectionOptional.get());
+      if(resultSetOptional.isPresent()) {
+        ActorRef resultSetActor = getContext().actorOf(Props.create(ResultSetIterator.class, self(),
+          resultSetOptional.get()).withDispatcher("akka.actor.result-dispatcher"));
+        deathWatch.tell(new RegisterActor(resultSetActor),self());
+        sender.tell(new ResultSetHolder(resultSetActor), self());
+      } else {
+        sender.tell(new NoResult(), self());
+        cleanUp();
+      }
+    } catch (SQLException e) {
+      LOG.error(operation.executionFailedErrorMessage(), e);
+      sender.tell(new ExecutionFailed(operation.executionFailedErrorMessage(), e), self());
+      cleanUp();
+    }
+  }
+
+  private abstract class Operation<T> {
+    abstract T getJob();
+    abstract Optional<ResultSet> call(HiveConnection connection) throws SQLException;
+    abstract String notConnectedErrorMessage();
+    abstract String executionFailedErrorMessage();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/YarnAtsParser.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/YarnAtsParser.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/YarnAtsParser.java
new file mode 100644
index 0000000..0f918ad
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/YarnAtsParser.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.actor;
+
+import akka.actor.UntypedActor;
+import org.apache.ambari.view.hive2.actor.message.HiveMessage;
+
+/**
+ * Queries YARN/ATS time to time to fetch the status of the ExecuteJob and updates database
+ */
+public class YarnAtsParser extends HiveActor {
+  @Override
+  public void handleMessage(HiveMessage hiveMessage) {
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AdvanceCursor.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AdvanceCursor.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AdvanceCursor.java
new file mode 100644
index 0000000..c3e6c04
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AdvanceCursor.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.actor.message;
+
+public class AdvanceCursor {
+
+    private String job;
+
+    public AdvanceCursor(String job) {
+        this.job = job;
+    }
+
+    public String getJob() {
+        return job;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AssignResultSet.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AssignResultSet.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AssignResultSet.java
new file mode 100644
index 0000000..fd1f26f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AssignResultSet.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.actor.message;
+
+import com.google.common.base.Optional;
+
+import java.sql.ResultSet;
+
+public class AssignResultSet {
+
+    private Optional<ResultSet> resultSet;
+
+
+    public AssignResultSet(Optional<ResultSet> resultSet) {
+        this.resultSet = resultSet;
+
+    }
+
+
+    public ResultSet getResultSet() {
+        return resultSet.orNull();
+    }
+
+
+    @Override
+    public String toString() {
+        return "ExtractResultSet{" +
+                "resultSet=" + resultSet +
+                '}';
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AssignStatement.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AssignStatement.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AssignStatement.java
new file mode 100644
index 0000000..85273ab
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AssignStatement.java
@@ -0,0 +1,46 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+import com.google.common.base.Optional;
+
+import java.sql.Statement;
+
+public class AssignStatement {
+
+    private Statement resultSet;
+
+    public AssignStatement(Statement statement) {
+        this.resultSet = statement;
+    }
+
+
+    public Statement getStatement() {
+        return resultSet;
+    }
+
+    @Override
+    public String toString() {
+        return "AssignStatement{" +
+                "resultSet=" + resultSet +
+                '}';
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AsyncJob.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AsyncJob.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AsyncJob.java
new file mode 100644
index 0000000..6dfd709
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/AsyncJob.java
@@ -0,0 +1,52 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+import org.apache.ambari.view.ViewContext;
+
+/**
+ * Message to be sent when a statement has to be executed
+ */
+public class AsyncJob extends DDLJob {
+  private final String jobId;
+  private final String logFile;
+
+  public AsyncJob(String jobId, String username, String[] statements, String logFile,ViewContext viewContext) {
+    super(Type.ASYNC, statements, username,viewContext);
+    this.jobId = jobId;
+    this.logFile = logFile;
+  }
+
+  public String getJobId() {
+    return jobId;
+  }
+
+  public String getLogFile() {
+    return logFile;
+  }
+
+
+  @Override
+  public String toString() {
+    return "AsyncJob{" +
+            "jobId='" + jobId + '\'' +
+            ", logFile='" + logFile + '\'' +
+            "} " + super.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/Connect.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/Connect.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/Connect.java
new file mode 100644
index 0000000..b859ac1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/Connect.java
@@ -0,0 +1,56 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+import org.apache.ambari.view.hive2.internal.Connectable;
+import org.apache.ambari.view.hive2.internal.HiveConnectionWrapper;
+
+/**
+ * Connect message to be sent to the Connection Actor with the connection parameters
+ */
+public class Connect {
+
+  private final String username;
+  private final String password;
+  private final String jdbcUrl;
+
+
+  public Connect(String username, String password, String jdbcUrl) {
+    this.username = username;
+    this.password = password;
+    this.jdbcUrl = jdbcUrl;
+  }
+
+  public Connectable getConnectable(){
+    return new HiveConnectionWrapper(getJdbcUrl(),username,password);
+  }
+
+  public String getUsername() {
+    return username;
+  }
+
+  public String getPassword() {
+    return password;
+  }
+
+  public String getJdbcUrl() {
+    return jdbcUrl;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/CursorReset.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/CursorReset.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/CursorReset.java
new file mode 100644
index 0000000..d805754
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/CursorReset.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
+ *
+ *     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.ambari.view.hive2.actor.message;
+
+public class CursorReset {
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/DDLJob.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/DDLJob.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/DDLJob.java
new file mode 100644
index 0000000..7e19a77
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/DDLJob.java
@@ -0,0 +1,73 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.ambari.view.ViewContext;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+
+public class DDLJob extends HiveJob {
+
+  public static final String SEMICOLON = ";";
+  private String[] statements;
+
+  public DDLJob(Type type, String[] statements, String username, ViewContext viewContext) {
+    super(type, username, viewContext);
+    this.statements = new String[statements.length];
+    for (int i = 0; i < statements.length; i++) {
+      this.statements[i] = clean(statements[i]);
+
+    }
+
+  }
+
+  private String clean(String statement) {
+    return StringUtils.trim(statement);
+  }
+
+  public Collection<String> getStatements() {
+    return Arrays.asList(statements);
+  }
+
+  /**
+   * Get the statements to be executed synchronously
+   *
+   * @return
+   */
+  public Collection<String> getSyncStatements() {
+    if (!(statements.length > 1))
+      return Collections.emptyList();
+    else
+      return ImmutableList.copyOf(Arrays.copyOfRange(statements, 0, statements.length - 1));
+  }
+
+  /**
+   * Get the statement to be executed asynchronously
+   *
+   * @return async statement
+   */
+  public String getAsyncStatement() {
+    return statements[statements.length - 1];
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ExecuteJob.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ExecuteJob.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ExecuteJob.java
new file mode 100644
index 0000000..d4d8a1b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ExecuteJob.java
@@ -0,0 +1,38 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+public class ExecuteJob {
+  public final static String SYNC_JOB_MARKER = "SYNC";
+  private final Connect connect;
+  private final HiveJob job;
+
+  public ExecuteJob(Connect connect, HiveJob job) {
+    this.connect = connect;
+    this.job = job;
+  }
+
+  public Connect getConnect() {
+    return connect;
+  }
+
+  public HiveJob getJob() {
+    return job;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ExecuteQuery.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ExecuteQuery.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ExecuteQuery.java
new file mode 100644
index 0000000..b3d1599
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ExecuteQuery.java
@@ -0,0 +1,23 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+public class ExecuteQuery {
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/FetchError.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/FetchError.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/FetchError.java
new file mode 100644
index 0000000..c78dc43
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/FetchError.java
@@ -0,0 +1,42 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+/**
+ *
+ * Fetch the result for
+ *
+ */
+public class FetchError {
+    private final String jobId;
+    private final String username;
+
+    public FetchError(String jobId, String username) {
+        this.jobId = jobId;
+        this.username = username;
+    }
+
+    public String getJobId() {
+        return jobId;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/FetchResult.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/FetchResult.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/FetchResult.java
new file mode 100644
index 0000000..6b2ac42
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/FetchResult.java
@@ -0,0 +1,42 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+/**
+ *
+ * Fetch the result for
+ *
+ */
+public class FetchResult {
+    private final String jobId;
+    private final String username;
+
+    public FetchResult(String jobId, String username) {
+        this.jobId = jobId;
+        this.username = username;
+    }
+
+    public String getJobId() {
+        return jobId;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/GetColumnMetadataJob.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/GetColumnMetadataJob.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/GetColumnMetadataJob.java
new file mode 100644
index 0000000..defa08c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/GetColumnMetadataJob.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.ambari.view.hive2.actor.message;
+
+import org.apache.ambari.view.ViewContext;
+
+public class GetColumnMetadataJob extends HiveJob {
+  private final String schemaPattern;
+  private final String tablePattern;
+  private final String columnPattern;
+  public GetColumnMetadataJob(String username, ViewContext viewContext,
+                              String schemaPattern, String tablePattern, String columnPattern) {
+    super(Type.SYNC, username, viewContext);
+    this.schemaPattern = schemaPattern;
+    this.tablePattern = tablePattern;
+    this.columnPattern = columnPattern;
+  }
+
+  public GetColumnMetadataJob(String username, ViewContext viewContext,
+                              String tablePattern, String columnPattern) {
+    this(username, viewContext, "*", tablePattern, columnPattern);
+  }
+
+  public GetColumnMetadataJob(String username, ViewContext viewContext,
+                              String columnPattern) {
+    this(username, viewContext, "*", "*", columnPattern);
+  }
+
+  public GetColumnMetadataJob(String username, ViewContext viewContext) {
+    this(username, viewContext, "*", "*", "*");
+  }
+
+  public String getSchemaPattern() {
+    return schemaPattern;
+  }
+
+  public String getTablePattern() {
+    return tablePattern;
+  }
+
+  public String getColumnPattern() {
+    return columnPattern;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/GetMoreLogs.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/GetMoreLogs.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/GetMoreLogs.java
new file mode 100644
index 0000000..6e084ee
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/GetMoreLogs.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
+ *
+ *     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.ambari.view.hive2.actor.message;
+
+
+public class GetMoreLogs {}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/HiveJob.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/HiveJob.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/HiveJob.java
new file mode 100644
index 0000000..ee3c1be
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/HiveJob.java
@@ -0,0 +1,63 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.ambari.view.ViewContext;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+public abstract class HiveJob {
+
+  private final String username;
+  private final Type type;
+  private final ViewContext viewContext;
+
+  public HiveJob(Type type, String username,ViewContext viewContext) {
+    this.type = type;
+    this.username = username;
+    this.viewContext = viewContext;
+  }
+
+  public String getUsername() {
+    return username;
+  }
+
+
+
+
+  public Type getType() {
+    return type;
+  }
+
+
+
+  public ViewContext getViewContext() {
+    return viewContext;
+  }
+
+
+  public enum Type {
+    SYNC,
+    ASYNC
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/HiveMessage.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/HiveMessage.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/HiveMessage.java
new file mode 100644
index 0000000..28533c7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/HiveMessage.java
@@ -0,0 +1,53 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+
+import java.util.UUID;
+
+/**
+ * Message wrapper, Each message has a unique ID
+ */
+public class HiveMessage {
+
+    private String id = UUID.randomUUID().toString();
+
+    private Object message;
+
+    public HiveMessage(Object message) {
+        this.message = message;
+    }
+
+
+    public Object getMessage() {
+        return message;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return "HiveMessage{" +
+                "message=" + message +
+                ", id='" + id + '\'' +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/JobExecutionCompleted.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/JobExecutionCompleted.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/JobExecutionCompleted.java
new file mode 100644
index 0000000..52ba3f5
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/JobExecutionCompleted.java
@@ -0,0 +1,21 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+public class JobExecutionCompleted {}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/JobRejected.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/JobRejected.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/JobRejected.java
new file mode 100644
index 0000000..4f9aab8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/JobRejected.java
@@ -0,0 +1,44 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+public class JobRejected {
+
+  private final String username;
+  private final String jobId;
+  private final String message;
+
+  public JobRejected(String username, String jobId, String message) {
+    this.username = username;
+    this.jobId = jobId;
+    this.message = message;
+  }
+
+  public String getUsername() {
+    return username;
+  }
+
+  public String getJobId() {
+    return jobId;
+  }
+
+  public String getMessage() {
+    return message;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/JobSubmitted.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/JobSubmitted.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/JobSubmitted.java
new file mode 100644
index 0000000..bc8df2a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/JobSubmitted.java
@@ -0,0 +1,38 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+public class JobSubmitted {
+
+  private final String username;
+  private final String jobId;
+
+  public JobSubmitted(String username, String jobId) {
+    this.username = username;
+    this.jobId = jobId;
+  }
+
+  public String getUsername() {
+    return username;
+  }
+
+  public String getJobId() {
+    return jobId;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/LogAggregationFinished.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/LogAggregationFinished.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/LogAggregationFinished.java
new file mode 100644
index 0000000..bfe37b5
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/LogAggregationFinished.java
@@ -0,0 +1,21 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+public class LogAggregationFinished {}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/RegisterActor.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/RegisterActor.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/RegisterActor.java
new file mode 100644
index 0000000..9988252
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/RegisterActor.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.actor.message;
+
+import akka.actor.ActorRef;
+
+public class RegisterActor {
+
+    private ActorRef actorRef;
+
+    public RegisterActor(ActorRef actorRef) {
+        this.actorRef = actorRef;
+    }
+
+    public ActorRef getActorRef() {
+        return actorRef;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ResetCursor.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ResetCursor.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ResetCursor.java
new file mode 100644
index 0000000..53276d3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ResetCursor.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
+ *
+ *     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.ambari.view.hive2.actor.message;
+
+public class ResetCursor {
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ResultReady.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ResultReady.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ResultReady.java
new file mode 100644
index 0000000..65de920
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/ResultReady.java
@@ -0,0 +1,47 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+import akka.actor.ActorRef;
+import org.apache.ambari.view.hive2.actor.message.job.AsyncExecutionFailed;
+import org.apache.ambari.view.hive2.internal.Either;
+
+/**
+ *
+ * Fetch the result for
+ *
+ */
+public class ResultReady extends FetchResult {
+    private Either<ActorRef, ActorRef> result;
+
+
+    public ResultReady(String jobId, String username, Either<ActorRef, ActorRef> result) {
+        super(jobId, username);
+        this.result = result;
+    }
+
+    public Either<ActorRef, ActorRef> getResult() {
+        return result;
+    }
+
+    public void setResult(Either<ActorRef, ActorRef> result) {
+        this.result = result;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/StartLogAggregation.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/StartLogAggregation.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/StartLogAggregation.java
new file mode 100644
index 0000000..3bae12a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/StartLogAggregation.java
@@ -0,0 +1,21 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+public class StartLogAggregation {}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/SyncJob.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/SyncJob.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/SyncJob.java
new file mode 100644
index 0000000..7aece31
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/SyncJob.java
@@ -0,0 +1,27 @@
+/*
+ * 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.ambari.view.hive2.actor.message;
+
+import org.apache.ambari.view.ViewContext;
+
+public class SyncJob extends DDLJob {
+  public SyncJob(String username, String[] statements,ViewContext viewContext) {
+    super(Type.SYNC, statements, username,viewContext);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/AsyncExecutionFailed.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/AsyncExecutionFailed.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/AsyncExecutionFailed.java
new file mode 100644
index 0000000..514d9cd
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/AsyncExecutionFailed.java
@@ -0,0 +1,46 @@
+/*
+ * 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.ambari.view.hive2.actor.message.job;
+
+public class AsyncExecutionFailed extends ExecutionFailed {
+  private final String jobId;
+  private final String username;
+
+  public AsyncExecutionFailed(String jobId,String username, String message, Throwable error) {
+    super(message, error);
+    this.jobId = jobId;
+    this.username = username;
+  }
+
+  public AsyncExecutionFailed(String jobId,String username, String message) {
+    super(message);
+    this.jobId = jobId;
+    this.username = username;
+  }
+
+
+
+  public String getJobId() {
+    return jobId;
+  }
+
+  public String getUsername() {
+    return username;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/ExecutionFailed.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/ExecutionFailed.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/ExecutionFailed.java
new file mode 100644
index 0000000..dcbf79f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/ExecutionFailed.java
@@ -0,0 +1,31 @@
+/*
+ * 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.ambari.view.hive2.actor.message.job;
+
+public class ExecutionFailed extends Failure {
+
+  public ExecutionFailed(String message, Throwable error) {
+    super(message, error);
+  }
+
+  public ExecutionFailed(String message) {
+    super(message, new Exception(message));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/Failure.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/Failure.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/Failure.java
new file mode 100644
index 0000000..af1e69d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/Failure.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.actor.message.job;
+
+public class Failure {
+  private final Throwable error;
+  private final String message;
+
+  public Failure(String message, Throwable error) {
+    this.message = message;
+    this.error = error;
+  }
+
+  public Throwable getError() {
+    return error;
+  }
+
+  public String getMessage() {
+    return message;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/FetchFailed.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/FetchFailed.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/FetchFailed.java
new file mode 100644
index 0000000..10a2d4e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/FetchFailed.java
@@ -0,0 +1,31 @@
+/*
+ * 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.ambari.view.hive2.actor.message.job;
+
+public class FetchFailed extends Failure{
+
+  public FetchFailed(String message, Throwable error) {
+    super(message, error);
+  }
+
+  public FetchFailed(String message) {
+    this(message, new Exception(message));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/Next.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/Next.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/Next.java
new file mode 100644
index 0000000..bfdc1ea
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/Next.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
+ *
+ *     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.ambari.view.hive2.actor.message.job;
+
+public class Next {
+}


[06/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/api-mock.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
new file mode 100644
index 0000000..ed4822d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
@@ -0,0 +1,291 @@
+/**
+ * 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.
+ */
+
+import applicationAdapter from 'hive/adapters/database';
+
+export default function() {
+  var baseUrl = applicationAdapter.create().buildURL();
+  var databases = ['db1', 'db2', 'db3'];
+
+  this.get(baseUrl + '/resources/ddl/database', function (req) {
+    var db = {
+      databases: databases
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(db)];
+  });
+
+  this.get(baseUrl + '/resources/ddl/database/db1/table.page', function (req) {
+    var tables = {
+      rows: [
+        ['table1'],
+        ['table2'],
+        ['table3']
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(tables)];
+  });
+
+  this.get(baseUrl + '/resources/ddl/database/db1/table', function (req) {
+    var tables = {
+      tables: [
+        ['table1'],
+        ['table2'],
+        ['table3']
+      ],
+      database: 'db1'
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(tables)];
+  });
+
+  this.get(baseUrl + '/resources/ddl/database/db1/table/table1.page', function (req) {
+    var columns = {
+      rows: [
+        ['column1', 'STRING'],
+        ['column2', 'STRING'],
+        ['column3', 'STRING']
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(columns)];
+  });
+
+  this.get(baseUrl + '/udfs', function (req) {
+    var udf = {
+      "udfs": [{
+        "name": "TestColumn",
+        "classname": "TestClassName",
+        "fileResource": 1,
+        "id": 1,
+        "owner": "owner1"
+      },
+      {
+        "name": "Test2Columns",
+        "classname": "Test2ClassName",
+        "fileResource": 1,
+        "id": 2,
+        "owner": "owner2"
+      }]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(udf)];
+  });
+
+  this.post(baseUrl + '/jobs', function (req) {
+    var job = {
+      "job": {
+        "status":"Finished",
+        "dataBase":"db1",
+        "dateSubmitted":1421677418,
+        "logFile":"job1/logs",
+        "properties":{},
+        "fileResources":[],
+        "statusDir":"job1",
+        "id":1,
+        "title":"Worksheet",
+        "duration":2,
+        "forcedContent":"",
+        "owner":"admin",
+        "confFile":"job1/conf",
+        "queryId":null,
+        "queryFile":"job1.hql"
+      }
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(job)];
+  });
+
+  this.get(baseUrl + '/resources/file/job1.hql', function (req) {
+    var file = {
+      "file": {
+        "filePath": "job1.hql",
+        "fileContent": "select * from big",
+        "hasNext": false,
+        "page": 0,
+        "pageCount": 1
+      }
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(file)];
+  });
+
+  this.get(baseUrl + '/savedQueries', function(req) {
+    var savedQueries = {
+      "savedQueries": [{
+        "queryFile": "saved1.hql",
+        "dataBase": "db1",
+        "title": "saved1",
+        "shortQuery": "",
+        "id": 1,
+        "owner": "owner1"
+      }, {
+        "queryFile": "saved2.hql",
+        "dataBase": "db2",
+        "title": "saved2",
+        "shortQuery": "select count(field_0) from big;",
+        "id": 2,
+        "owner": "owner2"
+      }]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(savedQueries)];
+  });
+
+  this.get(baseUrl + '/savedQueries/defaultSettings', function (req) {
+    var defaultSettings = {
+      "defaultSettings" : []
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(defaultSettings)];
+  });
+
+  this.get(baseUrl + '/resources/file/saved1.hql', function (req) {
+    var file = {
+      "file": {
+        "filePath": "saved1.hql",
+        "fileContent": "select * from saved1",
+        "hasNext": false,
+        "page": 0,
+        "pageCount": 0
+      }
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(file)];
+  });
+
+  this.get(baseUrl + '/jobs', function (req) {
+    var jobs = {
+      "jobs": [
+        {
+          "title": "Query1",
+          "queryFile": "saved1.hql",
+          "statusDir": "statusdir",
+          "dateSubmitted": 1421240048,
+          "duration": 97199,
+          "status": "Finished",
+          "forcedContent": "",
+          "id": 1,
+          "owner": "admin",
+          "logFile": "logs1",
+          "confFile": "conf1"
+        },
+        {
+          "title": "Query2",
+          "queryFile": "saved1.hql",
+          "statusDir": "statusdir",
+          "dateSubmitted": 1421240048,
+          "duration": 97199,
+          "status": "Finished",
+          "forcedContent": "",
+          "id": 2,
+          "owner": "admin",
+          "logFile": "logs2",
+          "confFile": "conf2"
+        },
+        {
+          "title": "Query3",
+          "queryFile": "saved1.hql",
+          "statusDir": "statusdir",
+          "dateSubmitted": 1421240048,
+          "duration": 97199,
+          "status": "Running",
+          "forcedContent": "",
+          "id": 3,
+          "owner": "admin",
+          "logFile": "logs3",
+          "confFile": "conf3"
+        },
+        {
+          "title": "Query4",
+          "queryFile": "saved1.hql",
+          "statusDir": "statusdir",
+          "dateSubmitted": 1421240048,
+          "duration": 97199,
+          "status": "Error",
+          "forcedContent": "",
+          "id": 4,
+          "owner": "admin",
+          "logFile": "logs4",
+          "confFile": "con51"
+        }
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(jobs)];
+  });
+
+  this.get(baseUrl + '/fileResources', function (req) {
+    var files = {
+      "fileResources": [
+        {
+          "name": "TestName",
+          "path": "TestPath",
+          "id": 1,
+          "owner": "owner1"
+        }
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(files)];
+  });
+
+  this.get(baseUrl + '/fileResources/1', function (req) {
+    var files = {
+      "fileResources": [
+        {
+          "name": "TestName",
+          "path": "TestPath",
+          "id": 1,
+          "owner": "owner1"
+        }
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(files)];
+  });
+
+  this.get(baseUrl + '/api/v1/views/TEZ', function (req) {
+    var data = {
+      versions: [
+        {
+          href: baseUrl + '/api/v1/view/TEZ/versions/1',
+          ViewVersionInfo: {version: '1', view_name: 'TEZ'}
+        }
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(data)];
+  });
+
+  this.get(baseUrl + '/api/v1/views/TEZ/versions/1', function (req) {
+    var data = {
+      instances: [
+        {
+          ViewInstanceInfo: {
+            instance_name: 'tez',
+            version: 1
+          }
+        }
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(data)];
+  });
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/resolver.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/resolver.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/resolver.js
new file mode 100644
index 0000000..f94998c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/resolver.js
@@ -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.
+ */
+
+import Resolver from 'ember/resolver';
+import config from '../../config/environment';
+
+var resolver = Resolver.create();
+
+resolver.namespace = {
+  modulePrefix: config.modulePrefix,
+  podModulePrefix: config.podModulePrefix
+};
+
+export default resolver;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/start-app.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/start-app.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/start-app.js
new file mode 100644
index 0000000..ab1a9d2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/start-app.js
@@ -0,0 +1,43 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import Application from '../../app';
+import Router from '../../router';
+import config from '../../config/environment';
+
+export default function startApp(attrs) {
+  var App;
+
+  var attributes = Ember.merge({}, config.APP);
+  attributes = Ember.merge(attributes, attrs); // use defaults, but you can override;
+
+  Router.reopen({
+    location: 'none'
+  });
+
+  Ember.run(function() {
+    App = Application.create(attributes);
+    App.setupForTesting();
+    App.injectTestHelpers();
+  });
+
+  // App.reset(); // this shouldn't be needed, i want to be able to "start an app at a specific URL"
+
+  return App;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/img/spinner.gif
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/img/spinner.gif b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/img/spinner.gif
new file mode 100644
index 0000000..e921e36
Binary files /dev/null and b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/img/spinner.gif differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/index.html
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/index.html b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/index.html
new file mode 100644
index 0000000..9faecc6
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/index.html
@@ -0,0 +1,71 @@
+<!--
+ * 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.
+-->
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title>Hive Tests</title>
+    <meta name="description" content="">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    {{content-for 'head'}}
+    {{content-for 'test-head'}}
+
+    <link rel="stylesheet" href="assets/vendor.css">
+    <link rel="stylesheet" href="assets/hive.css">
+    <link rel="stylesheet" href="assets/test-support.css">
+    <style>#blanket-main { position: relative; z-index: 99999; }</style>
+    <style>
+      #ember-testing-container {
+        position: absolute;
+        background: white;
+        bottom: 0;
+        right: 0;
+        width: 640px;
+        height: 384px;
+        overflow: auto;
+        z-index: 9999;
+        border: 1px solid #ccc;
+      }
+      #ember-testing {
+        zoom: 50%;
+      }
+    </style>
+
+    {{content-for 'head-footer'}}
+    {{content-for 'test-head-footer'}}
+  </head>
+  <body>
+    <div id="qunit"></div>
+    <div id="qunit-fixture"></div>
+
+    {{content-for 'body'}}
+    {{content-for 'test-body'}}
+    <script src="assets/vendor.js"></script>
+    <script src="assets/test-support.js"></script>
+    <script src="assets/hive.js"></script>
+    <script src="assets/blanket-options.js"></script>
+    <script src="assets/blanket-loader.js"></script>
+    <script src="testem.js"></script>
+    <script src="assets/test-loader.js"></script>
+
+    {{content-for 'body-footer'}}
+    {{content-for 'test-body-footer'}}
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/database-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/database-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/database-test.js
new file mode 100644
index 0000000..52cda77
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/database-test.js
@@ -0,0 +1,103 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { test } from 'ember-qunit';
+import startApp from '../helpers/start-app';
+import api from '../helpers/api-mock';
+
+var App;
+var server;
+
+module('Integration: Databases', {
+  setup: function() {
+    App = startApp();
+    /* global Pretender: true */
+    server = new Pretender(api);
+  },
+  teardown: function() {
+    Ember.run(App, App.destroy);
+    server.shutdown();
+  }
+});
+
+test('Database Explorer is displayed and populated with databases from server.', function (assert) {
+  assert.expect(2);
+
+  visit('/');
+
+  andThen(function() {
+    equal(find('.database-explorer').length, 1, 'Databases panel is visible.');
+    equal(find('.database-explorer .databases').children().length, 3, 'Databases are listed.');
+  });
+});
+
+test('Expanding a database will retrieve the first page of tables for that database.', function () {
+  expect(1);
+
+  visit('/');
+
+  andThen(function () {
+    var targetDB = find('.fa-database').first();
+
+    click(targetDB);
+
+    andThen(function () {
+      equal(find('.fa-table').length, 3);
+    });
+  });
+});
+
+test('Expanding a table will retrieve the first page of columns for that table.', function () {
+  expect(2);
+
+  visit('/');
+
+  andThen(function () {
+    var targetDB = find('.fa-database').first();
+
+    click(targetDB);
+
+    andThen(function () {
+      var targetTable = find('.fa-table').first();
+
+      click(targetTable);
+
+      andThen(function () {
+        equal(find('.columns').length, 1, 'Columns container was loaded.');
+        equal(find('.columns strong').length, 3, '3 columns were loaded for selected table.');
+      });
+    });
+  });
+});
+
+test('Searching for a table will display table results and column search field', function () {
+  expect(2);
+
+  visit('/');
+
+  andThen(function () {
+    fillIn(find('input').first(), 'table');
+    keyEvent(find('input').first(), 'keyup', 13);
+
+    andThen(function () {
+      equal(find('input').length, 2, 'Columns search input has been rendered.');
+      equal(find('.nav-tabs li').length, 2, 'Results tab has been redendered.');
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/history-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/history-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/history-test.js
new file mode 100644
index 0000000..35a950d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/history-test.js
@@ -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.
+ */
+
+import Ember from 'ember';
+import { test } from 'ember-qunit';
+import startApp from '../helpers/start-app';
+import api from '../helpers/api-mock';
+
+var App;
+var server;
+
+module('Integration: History', {
+  setup: function() {
+    App = startApp();
+    /* global Pretender: true */
+    server = new Pretender(api);
+  },
+
+  teardown: function() {
+    Ember.run(App, App.destroy);
+    server.shutdown();
+  }
+});
+
+test('Save Queries should list saved queries', function() {
+  expect(1);
+
+  visit("/history");
+
+  andThen(function() {
+    equal(find('#content .table tbody tr').length, 4);
+  });
+});
+
+test('User should be able to filter the jobs', function() {
+  expect(4);
+
+  visit("/history");
+
+  fillIn('column-filter input[placeholder=title]', "Query1");
+  keyEvent('column-filter input[placeholder=title]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by title');
+  });
+
+  click('.clear-filters');
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 4);
+  });
+
+
+  fillIn('column-filter input[placeholder=status]', "Finished");
+  keyEvent('column-filter input[placeholder=status]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2, 'User is able to filter by status');
+  });
+
+  click('.clear-filters');
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 4);
+  });
+});
+
+test('A query item should expand to show the HQL', function() {
+  expect(3);
+  visit("/history");
+
+  andThen(function() {
+    equal(find('.table-expandable tbody .secondary-row').length, 0, 'All queries are collapsed');
+  });
+
+  click('.table-expandable tbody tr:first-child');
+
+  andThen(function() {
+    equal(find('.table-expandable tbody .secondary-row').length, 1, 'One query is expanded');
+    ok(find('.table-expandable tbody tr:first-child').next().hasClass('secondary-row'), 'Clicked query is expanded');
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/query-editor-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/query-editor-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/query-editor-test.js
new file mode 100644
index 0000000..b409e12
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/query-editor-test.js
@@ -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.
+ */
+
+import Ember from 'ember';
+import { test } from 'ember-qunit';
+import startApp from '../helpers/start-app';
+import api from '../helpers/api-mock';
+
+var App;
+var server;
+
+module('Integration: Query Editor', {
+  setup: function() {
+    App = startApp();
+    /* global Pretender: true */
+    server = new Pretender(api);
+  },
+
+  teardown: function() {
+    Ember.run(App, App.destroy);
+    server.shutdown();
+  }
+});
+
+test('Query Editor is visible', function() {
+  expect(1);
+
+  visit("/");
+
+  andThen(function() {
+    equal(find('.query-editor-panel').length, 1, 'Query Editor is visible');
+  });
+});
+
+test('Can execute query either with full or partial selection', function() {
+  expect(3);
+
+  var query1 = "select count(*) from table1;",
+      query2 = "select color from z;",
+      query3 = "select fruit from z;",
+      query4 = query2 + "\n" + query3,
+      editor;
+
+  visit("/");
+
+  Ember.run(function() {
+    editor = find('.CodeMirror').get(0).CodeMirror;
+    editor.setValue(query1);
+  });
+
+  click('.execute-query');
+
+  andThen(function() {
+    equal(find('.query-process-results-panel').length, 1, 'Job tabs are visible.');
+  });
+
+  Ember.run(function() {
+    editor.setValue(query4);
+    editor.setSelection({ line: 1, ch: 0 }, { line: 1, ch: 20 });
+  });
+
+  click('.execute-query');
+
+  andThen(function() {
+    equal(editor.getValue(), query4, 'Editor value didn\'t change');
+    equal(editor.getSelection(), query3, 'Query 3 is selected');
+  });
+});
+
+
+test('Can save query', function() {
+  expect(2);
+
+  visit("/");
+
+  andThen(function() {
+    equal(find('.modal-dialog').length, 0, 'Modal dialog is hidden');
+  });
+
+  Ember.run(function() {
+    find('.CodeMirror').get(0).CodeMirror.setValue('select count(*) from table1');
+  });
+
+  click('.save-query-as');
+
+  andThen(function() {
+    equal(find('.modal-dialog').length, 1, 'Modal dialog is shown');
+  });
+
+  click('.modal-footer .btn-danger');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/saved-queries-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/saved-queries-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/saved-queries-test.js
new file mode 100644
index 0000000..c444523
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/saved-queries-test.js
@@ -0,0 +1,126 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { test } from 'ember-qunit';
+import startApp from '../helpers/start-app';
+import api from '../helpers/api-mock';
+
+var App;
+var server;
+
+module('Integration: Saved Queries', {
+  setup: function() {
+    App = startApp();
+    /* global Pretender: true */
+    server = new Pretender(api);
+  },
+
+  teardown: function() {
+    Ember.run(App, App.destroy);
+    server.shutdown();
+  }
+});
+
+test('Save Queries should list saved queries', function() {
+  expect(1);
+
+  visit("/queries");
+
+
+  andThen(function() {
+    equal(find('#content .table tbody tr').length, 2);
+  });
+});
+
+test('User should be able to filter the queries', function() {
+  expect(8);
+
+  visit("/queries");
+
+  fillIn('column-filter input[placeholder=preview]', "select count");
+  keyEvent('column-filter input[placeholder=preview]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by short query form.');
+  });
+
+  click('.clear-filters');
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2);
+  });
+
+  fillIn('column-filter input[placeholder=title]', "saved1");
+  keyEvent('column-filter input[placeholder=title]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by title');
+  });
+
+  click('.clear-filters');
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2);
+  });
+
+  fillIn('column-filter input[placeholder=database]', "db1");
+  keyEvent('column-filter input[placeholder=database]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by database');
+  });
+
+  click('.clear-filters');
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2);
+  });
+
+  fillIn('column-filter input[placeholder=owner]', "owner1");
+  keyEvent('column-filter input[placeholder=owner]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by owner');
+  });
+
+  click('.clear-filters');
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2);
+  });
+});
+
+test('User is able to load a query from saved queries', function() {
+  expect(1);
+
+  visit("/queries");
+  click('#content .table tbody tr:first-child td:first-child a');
+
+  andThen(function() {
+    equal(currentURL(), "/queries/1", 'User is redirected');
+  });
+});
+
+test('Saved Query options menu', function() {
+  expect(2);
+
+  visit("/queries");
+  click('.fa-gear');
+
+  andThen(function() {
+    equal(find('.dropdown-menu:visible').length, 1, 'Query menu is visible');
+    equal(find('.dropdown-menu:visible li').length, 2, 'Query menu has 2 options');
+  });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/tez-ui-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/tez-ui-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/tez-ui-test.js
new file mode 100644
index 0000000..f64dcb2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/tez-ui-test.js
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { test } from 'ember-qunit';
+import startApp from '../helpers/start-app';
+import api from '../helpers/api-mock';
+
+var App;
+var server;
+
+module('Integration: Tez UI', {
+  setup: function() {
+    App = startApp();
+    /* global Pretender: true */
+    server = new Pretender(api);
+  },
+
+  teardown: function() {
+    Ember.run(App, App.destroy);
+    server.shutdown();
+  }
+});
+
+test('An error is show when there is no dag', function() {
+  expect(1);
+
+  visit("/");
+  click('#tez-icon');
+
+  andThen(function() {
+    ok(find('.panel .alert .alert-danger'), 'Error is visible');
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/udfs-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/udfs-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/udfs-test.js
new file mode 100644
index 0000000..95a0043
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/udfs-test.js
@@ -0,0 +1,91 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { test } from 'ember-qunit';
+import startApp from '../helpers/start-app';
+import api from '../helpers/api-mock';
+
+var App;
+var server;
+
+module('Integration: Udfs', {
+  setup: function() {
+    App = startApp();
+    /* global Pretender: true */
+    server = new Pretender(api);
+  },
+
+  teardown: function() {
+    Ember.run(App, App.destroy);
+    server.shutdown();
+  }
+});
+
+test('Save Queries should list saved queries', function() {
+  expect(1);
+
+  visit("/udfs");
+
+  andThen(function() {
+    equal(find('#content .table tbody tr').length, 2);
+  });
+});
+
+test('User should be able to filter the udfs', function() {
+  expect(4);
+
+  visit("/udfs");
+
+  fillIn('column-filter input[placeholder="udf name"]', "TestColumn");
+  keyEvent('column-filter input[placeholder="udf name"]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by name');
+  });
+
+  click('.clear-filters');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2);
+  });
+
+  fillIn('column-filter input[placeholder="udf class name"]', "TestClassName");
+  keyEvent('column-filter input[placeholder="udf class name"]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by class name');
+  });
+
+  click('.clear-filters');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2);
+  });
+});
+
+test('User is able to add udf', function() {
+  expect(1);
+
+  visit("/udfs");
+  click('.add-udf');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr').length, 3);
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/test-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/test-helper.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/test-helper.js
new file mode 100644
index 0000000..96975ee
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/test-helper.js
@@ -0,0 +1,24 @@
+/**
+ * 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.
+ */
+
+import resolver from './helpers/resolver';
+import {
+  setResolver
+} from 'ember-qunit';
+
+setResolver(resolver);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/application.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/application.js
new file mode 100644
index 0000000..6e28a40
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/application.js
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {
+  moduleFor,
+  test
+} from 'ember-qunit';
+
+import constants from 'hive/utils/constants';
+
+moduleFor('adapter:application', 'ApplicationAdapter', {
+  // Specify the other units that are required for this test.
+  // needs: ['serializer:foo']
+});
+
+// Replace this with your real tests.
+test('X-Requested-By header is set.', function() {
+  expect(1);
+
+  var adapter = this.subject();
+
+  ok(adapter.get('headers.X-Requested-By'), 'X-Requested-By is set to a truthy value.');
+});
+
+test('buildUrl returns an url with default values for version and instance paramters if not running within an Ambari instance.', function () {
+  expect(1);
+
+  var adapter = this.subject();
+
+  var url = adapter.buildURL();
+
+  equal(url, constants.adapter.apiPrefix + constants.adapter.version + constants.adapter.instancePrefix + 'Hive');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/file.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/file.js
new file mode 100644
index 0000000..ea70232
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/file.js
@@ -0,0 +1,39 @@
+/**
+ * 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.
+ */
+
+import {
+  moduleFor,
+  test
+} from 'ember-qunit';
+
+import constants from 'hive/utils/constants';
+
+moduleFor('adapter:file', 'FileAdapter', {
+  // Specify the other units that are required for this test.
+  // needs: ['serializer:foo']
+});
+
+// Replace this with your real tests.
+test('pathForType returns correct path.', function() {
+  expect(1);
+
+  var adapter = this.subject();
+  var type = 'dummy';
+
+  equal(adapter.pathForType(type), constants.adapter.resourcePrefix + type);
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/alert-message-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/alert-message-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/alert-message-widget-test.js
new file mode 100644
index 0000000..8f0f245
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/alert-message-widget-test.js
@@ -0,0 +1,91 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('alert-message-widget', 'AlertMessageWidgetComponent', {
+  needs: []
+});
+
+test('isExpanded is toggled on click', function() {
+  expect(2);
+
+  var message = Ember.Object.create({ isExpanded: false});
+
+  var component = this.subject({
+    message: message
+  });
+
+  Ember.run(function() {
+    component.send('toggleMessage');
+  });
+
+  equal(component.get('message.isExpanded'), true, 'isExpanded is set to true');
+
+  Ember.run(function() {
+    component.send('toggleMessage');
+  });
+
+  equal(component.get('message.isExpanded'), false, 'isExpanded is set to false');
+});
+
+test('removeLater should be called when the message is toggled', function() {
+  expect(1);
+
+  var message = Ember.Object.create({ isExpanded: false});
+
+  var targetObject = {
+    removeLater: function() {
+      ok(true, 'External removeLater called');
+    }
+  };
+
+  var component = this.subject({
+    targetObject: targetObject,
+    removeLater: 'removeLater',
+    message: message
+  });
+
+  Ember.run(function() {
+    component.send('toggleMessage');
+  });
+
+  Ember.run(function() {
+    component.send('toggleMessage');
+  });
+});
+
+test('remove action should call external removeMessage', function() {
+  expect(1);
+
+  var targetObject = {
+    removeMessage: function() {
+      ok(true, 'External removeMessage called');
+    }
+  };
+
+  var component = this.subject({
+    targetObject: targetObject,
+    removeMessage: 'removeMessage'
+  });
+
+  Ember.run(function() {
+    component.send('remove', {});
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js
new file mode 100644
index 0000000..96a551f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js
@@ -0,0 +1,46 @@
+/**
+ * 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.
+ */
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('collapsible-widget', 'CollapsibleWidgetComponent', {
+  unit: true
+});
+
+test('Component expand/collapse toggle action', function () {
+  expect(1);
+
+  var targetObject = {
+    expanded: function() {
+      ok(true, 'External expanded called');
+    }
+  };
+
+  var component = this.subject({
+    targetObject: targetObject,
+    isExpanded: 'isExpanded',
+    expanded: 'expanded'
+  });
+
+  var $component = this.render();
+
+  Ember.run(function() {
+    component.set('isExpanded', false);
+    component.send('toggle', {});
+   });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js
new file mode 100644
index 0000000..be8bdc4
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js
@@ -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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('column-filter-widget', 'ColumnFilterWidgetComponent', {
+  needs: ['component:extended-input']
+});
+
+test('if a filterValue is set when the element is inserted, an action is being sent announcing a filter change', function () {
+  expect(1);
+
+  var column = Ember.Object.create({
+    caption: 'missing.translation'
+  });
+
+  var component = this.subject({ column: column });
+
+  Ember.run(function () {
+    component.set('filterValue', 'initial filter value');
+  });
+
+  var targetObject = {
+    externalAction: function(){
+      ok(true, 'initial filterValue set. Action has been sent.');
+    }
+  };
+
+  component.set('columnFiltered', 'externalAction');
+  component.set('targetObject', targetObject);
+
+  var $component = this.$();
+});
+
+test('isSorted returns true if the table is sorted by this column property', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var column = Ember.Object.create({
+    property: 'some prop'
+  });
+
+  Ember.run(function () {
+    component.set('column', column);
+    component.set('sortProperties', [column.property]);
+  });
+
+  ok(component.get('isSorted'));
+});
+
+test('isSorted returns false if the table is sorted by some other column', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var column = Ember.Object.create({
+    property: 'some prop'
+  });
+
+  Ember.run(function () {
+    component.set('column', column);
+    component.set('sortProperties', ['other prop']);
+  });
+
+  ok(!component.get('isSorted'));
+});
+
+test('isSorted returns false if the table is not sorted by any column', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var column = Ember.Object.create({
+    property: 'some prop'
+  });
+
+  Ember.run(function () {
+    component.set('column', column);
+    component.set('sortProperties', []);
+  });
+
+  ok(!component.get('isSorted'));
+});
+
+test('when sendSort gets called, the columnSorted action gets sent.', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var targetObject = {
+    externalAction: function(){
+      ok(true, 'columnSorted action has been intercepted.');
+    }
+  };
+
+  Ember.run(function () {
+    component.set('targetObject', targetObject);
+    component.set('columnSorted', 'externalAction');
+
+    component.send('sendSort');
+  });
+});
+
+test('when sendFilter gets called, the columnFiltered action gets sent.', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var targetObject = {
+    externalAction: function(){
+      ok(true, 'columnFiltered action has been intercepted.');
+    }
+  };
+
+  Ember.run(function () {
+    component.set('targetObject', targetObject);
+    component.set('columnFiltered', 'externalAction');
+
+    component.send('sendFilter');
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
new file mode 100644
index 0000000..766e9ee
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
@@ -0,0 +1,132 @@
+/**
+ * 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.
+ */
+
+/* global moment */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('date-range-widget', 'DateRangeWidgetComponent', {
+  needs: ['component:extended-input']
+});
+
+test('Date fields are set correctly', function() {
+  expect(2);
+
+  var component = this.subject();
+
+  var min = moment('04/11/2014', 'DD/MM/YYYY');
+  var max = moment('04/12/2014', 'DD/MM/YYYY');
+  var from = moment('04/11/2014', 'DD/MM/YYYY');
+  var to = moment('04/12/2014', 'DD/MM/YYYY');
+
+  var dateRange = Ember.Object.create({
+    from: from.toString(),
+    to: to.toString(),
+    min: min.toString(),
+    max: max.toString()
+  });
+
+  component.set('dateRange', Ember.Object.create());
+
+  var $component = this.$();
+
+  Ember.run(function() {
+    component.set('dateRange', dateRange);
+  });
+
+  equal($component.find('.fromDate').val(), moment(from).format('MM/DD/YYYY'), "From date is set correctly");
+  equal($component.find('.toDate').val(), moment(to).format('MM/DD/YYYY'), "To date is set correctly");
+});
+
+test('Date fields updates when the date is changed', function() {
+  expect(2);
+
+  var component = this.subject();
+
+  var min = moment('04/11/2014', 'DD/MM/YYYY');
+  var max = moment('04/12/2014', 'DD/MM/YYYY');
+  var from = moment('04/11/2014', 'DD/MM/YYYY');
+  var to = moment('04/12/2014', 'DD/MM/YYYY');
+
+  var dateRange = Ember.Object.create({
+    from: from.toString(),
+    to: to.toString(),
+    min: min.toString(),
+    max: max.toString()
+  });
+
+  Ember.run(function() {
+    component.set('dateRange', dateRange);
+  });
+
+  var $component = this.$();
+  $component.find('.fromDate').datepicker('setDate', '10/10/2014');
+  $component.find('.toDate').datepicker('setDate', '11/11/2014');
+
+  equal($component.find('.fromDate').val(), '10/10/2014', "From date field is updated");
+  equal($component.find('.toDate').val(), '11/11/2014', "To date field is updated");
+});
+
+test('Display dates are formatted correctly', function(){
+  expect(2);
+
+  var component = this.subject();
+
+  var min = moment('04/11/2014', 'DD/MM/YYYY');
+  var max = moment('04/12/2014', 'DD/MM/YYYY');
+  var from = moment('04/11/2014', 'DD/MM/YYYY');
+  var to = moment('04/12/2014', 'DD/MM/YYYY');
+
+  var dateRange = Ember.Object.create({
+    from: from.toString(),
+    to: to.toString(),
+    min: min.toString(),
+    max: max.toString()
+  });
+
+  Ember.run(function () {
+    component.set('dateRange', dateRange);
+  });
+
+  equal(component.get('displayFromDate'), '11/04/2014', "displayFromDate is formatted correctly");
+  equal(component.get('displayToDate'), '12/04/2014', "displayToDate is formatted correctly");
+});
+
+test('If from/to are not passed they are set to min/max', function() {
+  expect(2);
+
+  var component = this.subject();
+
+  var min = moment('04/11/2014', 'DD/MM/YYYY');
+  var max = moment('04/12/2014', 'DD/MM/YYYY');
+
+  var dateRange = Ember.Object.create({
+    min: min.toString(),
+    max: max.toString()
+  });
+
+  Ember.run(function () {
+    component.set('dateRange', dateRange);
+  });
+
+  var $component = this.$();
+
+  equal(component.get('dateRange.from'), min.toString(), "From date is to min date");
+  equal(component.get('dateRange.to'), max.toString(), "To date is set to max date");
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js
new file mode 100644
index 0000000..8d1f07a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('expander-widget', 'ExpanderWidgetComponent', {
+  unit: true
+});
+
+test('should set the heading when provided.', function () {
+  expect(2);
+
+  var component = this.subject();
+  var $component = this.$();
+  var heading = 'some header';
+
+  equal($component.find('.accordion-toggle').text(), '');
+
+  Ember.run(function () {
+    component.set('heading', heading);
+  });
+
+  equal($component.find('.accordion-toggle').text(), heading);
+});
+
+test('should correctly toggle isExpanded property.', function () {
+  expect(2);
+
+  var component = this.subject();
+  this.$();
+
+  Ember.run(function(){
+    component.send('toggle');
+  });
+
+  equal(component.get('isExpanded'), true);
+
+  Ember.run(function(){
+    component.send('toggle');
+  });
+
+  equal(component.get('isExpanded'), false);
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
new file mode 100644
index 0000000..aa861aa
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
@@ -0,0 +1,81 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('extended-input', 'ExtendedInputComponent', {
+  unit: true
+});
+
+test('Component has dynamicValue and dynamicContext', function () {
+  expect(1);
+
+  var component = this.subject({
+    dynamicValue: 'dynamicValue',
+    dynamicContext: Ember.Object.create({ 'dynamicValue' : 'test' })
+  });
+
+  var $component = this.$();
+
+  equal(component.get('value'), 'test', 'Value is set to dynamicValue value');
+});
+
+
+test('Component has no dynamicValue and dynamicContext', function () {
+  expect(1);
+
+  var component = this.subject();
+  var $component = this.$();
+
+  ok(!component.get('value'), 'Value is not set as dynamicValue value');
+});
+
+test("Component's dynamicValue is set", function () {
+  expect(1);
+
+  var component = this.subject({
+    dynamicValue: 'dynamicValue',
+    dynamicContext: Ember.Object.create({ 'dynamicValue' : 'test' })
+  });
+
+  var $component = this.$();
+
+  Ember.run(function() {
+    component.sendValueChanged();
+
+    equal(component.get('value'), component.dynamicContext.get('dynamicValue'), "Value is set and dynamicValue is set");
+  });
+});
+
+test("Component's dynamicValue is not set", function () {
+  expect(1);
+
+  var component = this.subject({
+    dynamicValue: 'dynamicValue',
+    dynamicContext: Ember.Object.create({ })
+  });
+
+  var $component = this.$();
+
+  Ember.run(function() {
+    component.sendValueChanged();
+
+    equal(component.get('value'), undefined, "Value is not set");
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/job-tr-view-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/job-tr-view-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/job-tr-view-test.js
new file mode 100644
index 0000000..d39a85e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/job-tr-view-test.js
@@ -0,0 +1,62 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('job-tr-view', 'JobTrViewComponent', {
+  unit: true
+});
+
+test('Statuses are computed correctly', function (assert) {
+  assert.expect(5);
+
+  var component = this.subject();
+
+  Ember.run(function() {
+    component.set('job', Ember.Object.create());
+    component.set('job.status', constants.statuses.running);
+  });
+
+  assert.equal(component.get('canStop'), true, 'Status is running canStop returns true');
+
+  Ember.run(function() {
+    component.set('job.status', constants.statuses.initialized);
+  });
+
+  assert.equal(component.get('canStop'), true, 'Status is initialized canStop returns true');
+
+  Ember.run(function() {
+    component.set('job.status', constants.statuses.pending);
+  });
+
+  assert.equal(component.get('canStop'), true, 'Status is pending canStop returns true');
+
+  Ember.run(function() {
+    component.set('job.status', constants.statuses.canceled);
+  });
+
+  assert.equal(component.get('canStop'), false, 'Status is canceled canStop returns false');
+
+  Ember.run(function() {
+    component.set('job.status', constants.statuses.unknown);
+  });
+
+  assert.equal(component.get('canStop'), false, 'Status is unknown canStop returns false');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/modal-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/modal-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/modal-widget-test.js
new file mode 100644
index 0000000..3016444
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/modal-widget-test.js
@@ -0,0 +1,69 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('modal-widget', 'ModalWidgetComponent', {
+  needs: ['helper:tb-helper']
+});
+
+test('It send ok action on keyPress enter', function(assert) {
+  assert.expect(1);
+
+  Ember.run.debounce = function(target, func) {
+    func.call(target);
+  };
+
+  var component = this.subject({
+    ok: 'ok',
+    targetObject: {
+      ok: function() {
+        assert.ok(1, 'OK action sent');
+      }
+    }
+  });
+
+  var $component = this.$();
+
+  component.keyPress({ which: 13 });
+  Ember.$('.modal-backdrop').remove(); // remove overlay
+});
+
+test('It send close action on keyPress escape', function(assert) {
+  assert.expect(1);
+
+  Ember.run.debounce = function(target, func) {
+    func.call(target);
+  };
+
+  var component = this.subject({
+    close: 'close',
+    targetObject: {
+      close: function() {
+        assert.ok(1, 'Close action sent');
+      }
+    }
+  });
+
+  var $component = this.$();
+
+  component.keyPress({ which: 27 });
+  Ember.$('.modal-backdrop').remove(); // remove overlay
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js
new file mode 100644
index 0000000..47a1a0f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js
@@ -0,0 +1,44 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('no-bubbling', 'NoBubblingWidgetComponent', {
+  unit: true
+});
+
+
+test('External actions', function() {
+  expect(2);
+
+  var component = this.subject({
+    targetObject: {
+      click: function(data) {
+        ok(true, 'External click action called');
+        equal(data, 'data', 'Data is sent with the action');
+      }
+    },
+    click: 'click',
+    data: 'data'
+  });
+
+  var $component = this.$();
+
+  $component.trigger('click');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
new file mode 100644
index 0000000..edc65b1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     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.
+ */
+
+/* global moment */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('number-range-widget', 'NumberRangeWidgetComponent', {
+  needs: ['component:extended-input']
+});
+
+
+test('Component is initialized correctly', function() {
+  expect(2);
+
+  var numberRange = Ember.Object.create({
+    max: 1,
+    min: 0
+  });
+
+  var component = this.subject({ numberRange: numberRange });
+  var $component = this.$();
+
+  equal(component.get('numberRange.from'), numberRange.get('min'), 'from is set to min');
+  equal(component.get('numberRange.to'), numberRange.get('max'), 'to is set to max');
+
+});
+
+test('external change action is called', function() {
+  expect(1);
+
+  var targetObject = {
+    rangeChanged: function() {
+      ok(true, 'rangeChanged external action called');
+    }
+  };
+
+  var numberRange = Ember.Object.create({
+    max: 1,
+    min: 0
+  });
+
+  var component = this.subject({
+    numberRange: numberRange,
+    targetObject: targetObject,
+    rangeChanged: 'rangeChanged'
+  });
+
+  var $component = this.$();
+
+  Ember.run(function() {
+    $component.find('.slider').slider('value', 1);
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js
new file mode 100644
index 0000000..84bec76
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('popover-widget', 'PopoverWidgetComponent', {
+  unit: true
+});
+
+test('Component initializes correctly', function () {
+  expect(2);
+
+  var component = this.subject({
+    template: Ember.Handlebars.compile("test")
+  });
+  var $component = this.$();
+
+  ok($component, "Popover element is initialized");
+  equal($component.attr('data-content').trim(), "test", "data-content is populated");
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
new file mode 100644
index 0000000..3984f62
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
@@ -0,0 +1,40 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('progress-widget', 'ProgressWidgetComponent', {
+  unit: true
+});
+
+test('Percentage is updated on value change', function() {
+  var component = this.subject({
+    value: 0
+  });
+
+  this.$();
+
+  equal(component.get('percentage'), '0%', 'Progress is at 0%');
+
+  Ember.run(function() {
+    component.set('value', 50);
+  });
+
+  equal(component.get('percentage'), '50%', 'Progress is at 50%');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js
new file mode 100644
index 0000000..e70b5ee
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js
@@ -0,0 +1,52 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('query-editor', 'QueryEditorComponent', {
+  unit: true
+});
+
+test('initEditor sets the editor on didInsertElement', function () {
+  expect(2);
+
+  var component = this.subject();
+
+  equal(component.get('editor'), undefined, 'element not rendered. Editor not set.');
+
+  this.$();
+
+  ok(component.get('editor'), 'element rendered. Editor set.');
+});
+
+test('updateValue sets the query value on the editor.', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var query = 'select something';
+
+  this.$();
+
+  Ember.run(function () {
+    component.set(('query'), query);
+  });
+
+  equal(component.get('editor').getValue(), query, 'set query property. Updated editor value property.');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js
new file mode 100644
index 0000000..a186508
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js
@@ -0,0 +1,158 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('select-widget', 'SelectWidgetComponent', {
+  needs: ['helper:path-binding']
+});
+
+test('selectedLabel returns the selectedValue property indicated by labelPath if selectedValue and labelPath are set.', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var selectedValue = Ember.Object.extend({
+    label: 'db'
+  }).create();
+
+  var labelPath = 'label';
+
+  Ember.run(function () {
+    component.set('labelPath', labelPath);
+    component.set('selectedValue', selectedValue);
+  });
+
+  equal(component.get('selectedLabel'), selectedValue.label, 'selectedValue and labelPath are set. selectedLabel returns selectedValue[labelPath].');
+});
+
+test('selectedLabel returns defaultLabel if selectedValue is falsy and defaultLabel is set.', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var defaultLabel = 'select...';
+
+  Ember.run(function () {
+    component.set('defaultLabel', defaultLabel);
+  });
+
+  equal(component.get('selectedLabel'), defaultLabel, 'selectedValue falsy and defaultLabel set. selectedLabel returns defaultLabel.');
+});
+
+test('selectedLabel returns undefined if neither selectedValue nor defaultLabel are set.', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  equal(component.get('selectedLabel'), undefined, 'selectedValue and defaultLabel are falsy. selectedLabel returns undefined.');
+});
+
+test('selectedLabel is computed when selectedValue changes.', function () {
+  expect(2);
+
+  var component = this.subject();
+
+  var selectedValue = Ember.Object.extend({
+    label: 'db'
+  }).create();
+
+  var labelPath = 'label';
+
+  equal(component.get('selectedLabel'), undefined, 'selectedValue and defaultLabel are falsy. selectedLabel returns undefined.');
+
+  Ember.run(function () {
+    component.set('labelPath', labelPath);
+    component.set('selectedValue', selectedValue);
+  });
+
+  equal(component.get('selectedLabel'), selectedValue.label, 'selectedValue and labelPath are set. selectedLabel returns selectedValue[labelPath].');
+});
+
+test('renders an li tag for each item in the items collection.', function () {
+  expect(2);
+
+  var component = this.subject();
+  var $component = this.$();
+
+  equal($component.find('li').length, 0, 'items collection is not set. No li tags are rendered.');
+
+  Ember.run(function() {
+    var items = Ember.ArrayProxy.create({ content: Ember.A([Ember.Object.create(), Ember.Object.create()])});
+    component.set('labelPath', 'name');
+    component.set('items', items);
+  });
+
+  equal($component.find('li').length, 2, 'items collection is set containing one item. One li tag is rendered.');
+});
+
+test('if no selected item nor defaultLabel set the selected value with first item', function () {
+  expect(1);
+
+  var items = [
+    'item1',
+    'item2'
+  ];
+
+  var component = this.subject({ items: items });
+  var $component = this.$();
+
+  equal(component.get('selectedValue'), 'item1', 'selectedValue is set to first item')
+});
+
+test('component actions', function() {
+  expect(7);
+
+  var targetObject = {
+    itemAdded: function() {
+      ok(true, 'External action itemAdded called')
+    },
+    itemEdited: function(item) {
+      ok(true, 'External action itemEdited called');
+      equal(item, 'editedItem', 'Data is sent with action');
+    },
+    itemRemoved: function(item) {
+      ok(true, 'External action itemRemoved called');
+      equal(item, 'removedItem', 'Data is sent with action');
+    }
+  };
+  var component = this.subject({
+    items: ['item'],
+    itemAdded: 'itemAdded',
+    itemEdited: 'itemEdited',
+    itemRemoved: 'itemRemoved',
+    targetObject: targetObject
+  });
+
+  var $component = this.$();
+
+  equal(component.get('selectedValue'), 'item', 'selectedValue is set to first item');
+
+  Ember.run(function() {
+    component.send('select', 'newItem');
+    component.send('add');
+    component.send('edit', 'editedItem');
+    component.send('remove', 'removedItem');
+  });
+
+  equal(component.get('selectedValue'), 'newItem', 'selectedValue is set to newItem');
+
+
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js
new file mode 100644
index 0000000..17b2242
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js
@@ -0,0 +1,117 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('tabs-widget', 'TabsWidgetComponent', {
+  needs: []
+});
+
+test('First tab active by default', function() {
+  expect(2);
+
+  var tabs = Ember.ArrayProxy.create({content: Ember.A([
+    Ember.Object.create(),
+    Ember.Object.create()
+  ])});
+
+  var component = this.subject({ tabs: tabs });
+  var $component = this.$();
+
+  ok(component.get('tabs.firstObject.active'), 'First tab is active');
+  ok(!component.get('tabs.lastObject.active'), 'Second tab is not active');
+});
+
+
+test('Set active tab on init', function() {
+  expect(2);
+
+  var tabs = Ember.ArrayProxy.create({content: Ember.A([
+    Ember.Object.create(),
+    Ember.Object.create(),
+    Ember.Object.create({ active: true })
+  ])});
+
+  var component = this.subject({ tabs: tabs });
+
+  ok(!component.get('tabs.firstObject.active'), 'First tab is not active');
+  ok(component.get('tabs.lastObject.active'), 'Last tab is active');
+});
+
+
+test('Set active tab', function() {
+  expect(3);
+
+  var tabs = Ember.ArrayProxy.create({content: Ember.A([
+    Ember.Object.create(),
+    Ember.Object.create(),
+    Ember.Object.create({ active: true })
+  ])});
+
+  var component = this.subject({ tabs: tabs });
+
+  ok(!component.get('tabs.firstObject.active'), 'First tab is not active');
+  ok(component.get('tabs.lastObject.active'), 'Last tab is active');
+
+  Ember.run(function() {
+    component.send('selectTab', tabs.objectAt(1));
+  });
+
+  ok(component.get('tabs').objectAt(1).get('active'), 'Second tab is active');
+});
+
+test('removeEnabled tabs', function() {
+  expect(2);
+
+  var tabs = Ember.ArrayProxy.create({content: Ember.A([
+    Ember.Object.create(),
+    Ember.Object.create(),
+    Ember.Object.create({ active: true })
+  ])});
+
+  var component = this.subject({ tabs: tabs, canRemove: true });
+
+  ok(component.get('removeEnabled'), 'More than one tab removeEnabled returns true');
+
+  Ember.run(function() {
+    component.get('tabs').popObject();
+    component.get('tabs').popObject();
+  });
+
+  ok(!component.get('removeEnabled'), 'Only one tab removeEnabled returns false');
+});
+
+test('remove tab', function () {
+  expect(1);
+
+  var targetObject = {
+    removeTabAction: function() {
+      ok(true, 'External remove tab action called');
+    }
+  };
+
+  var component = this.subject({
+    'removeClicked': 'removeTabAction',
+    'targetObject': targetObject
+  });
+
+  Ember.run(function() {
+    component.send('remove', {});
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
new file mode 100644
index 0000000..7d989a4
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
@@ -0,0 +1,46 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('typeahead-widget', 'TypeaheadWidgetComponent', {
+  needs: ['component:ember-selectize']
+});
+
+test('Component is initialized correctly', function () {
+  expect(2);
+
+  var items = [
+    {name: 'item 1', id: 1},
+    {name: 'item 2', id: 2},
+    {name: 'item 3', id: 3},
+    {name: 'item 4', id: 4}
+  ];
+
+  var component = this.subject({
+    content: items,
+    optionValuePath: 'content.id',
+    optionLabelPath: 'content.name'
+  });
+
+  this.$();
+
+  equal(component.get('content.length'), items.length, 'Items are set');
+  equal(component.get('selection'), items[0], 'First object is set as default value');
+});


[13/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/Parser.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/Parser.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/Parser.java
new file mode 100644
index 0000000..79c5482
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/Parser.java
@@ -0,0 +1,154 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers;
+
+import org.apache.ambari.view.hive2.client.ColumnDescription;
+import org.apache.ambari.view.hive2.client.Row;
+import org.apache.ambari.view.hive2.resources.uploads.ColumnDescriptionImpl;
+import org.apache.ambari.view.hive2.resources.uploads.TableDataReader;
+
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * provides general implementation for parsing JSON,CSV,XML file
+ * to generate preview rows, headers and column types
+ * also provides TableDataReader for converting any type to CSV.
+ */
+public abstract class Parser implements IParser {
+
+  protected Reader reader; // same as CSV reader in this case
+  protected ParseOptions parseOptions;
+  private int numberOfPreviewRows = 10;
+
+  public Parser(Reader originalReader, ParseOptions parseOptions) {
+    this.reader = originalReader;
+    this.parseOptions = parseOptions;
+  }
+
+  /**
+   * returns which datatype was detected for the maximum number of times in the given column
+   *
+   * @param typeCounts
+   * @param colNum
+   * @return
+   */
+  private int getLikelyDataType(int[][] typeCounts, int colNum) {
+    int[] colArray = typeCounts[colNum];
+    int maxIndex = 0;
+    int i = 1;
+    for (; i < colArray.length; i++) {
+      if (colArray[i] > colArray[maxIndex])
+        maxIndex = i;
+    }
+
+    return maxIndex;
+  }
+
+  @Override
+  public Reader getTableDataReader() {
+    return new TableDataReader(this.iterator());
+  }
+
+  @Override
+  public PreviewData parsePreview() {
+    List<Row> previewRows;
+    List<ColumnDescription> header;
+
+    try {
+      numberOfPreviewRows = (Integer) parseOptions.getOption(ParseOptions.OPTIONS_NUMBER_OF_PREVIEW_ROWS);
+    } catch (Exception e) {
+    }
+
+    int numberOfRows = numberOfPreviewRows;
+    previewRows = new ArrayList<Row>(numberOfPreviewRows + 1); // size including the header.
+
+    Row headerRow = null;
+    Integer numOfCols = null;
+    int[][] typeCounts = null;
+
+    if (parseOptions.getOption(ParseOptions.OPTIONS_HEADER) != null && parseOptions.getOption(ParseOptions.OPTIONS_HEADER).equals(ParseOptions.HEADER.FIRST_RECORD.toString())) {
+      if (!this.iterator().hasNext()) {
+        throw new NoSuchElementException("Cannot parse Header");
+      }
+      headerRow = extractHeader();
+      numOfCols = headerRow.getRow().length;
+      typeCounts = new int[numOfCols][ColumnDescription.DataTypes.values().length];
+      previewRows.add(headerRow);
+    }
+
+    // find data types.
+
+    Row r;
+    if (iterator().hasNext()) {
+      r = iterator().next();
+      if( null == numOfCols ) {
+        numOfCols = r.getRow().length;
+        typeCounts = new int[numOfCols][ColumnDescription.DataTypes.values().length];
+      }
+    } else {
+        throw new NoSuchElementException("No rows in the file.");
+    }
+
+    while (true) {
+      // create Header definition from row
+      Object[] values = r.getRow();
+
+      Object[] newValues= new Object[numOfCols]; // adds null if less columns detected and removes extra columns if any
+
+      for (int colNum = 0; colNum < numOfCols; colNum++) {
+        if(colNum < values.length) {
+          // detect type
+          ColumnDescription.DataTypes type = ParseUtils.detectHiveDataType(values[colNum]);
+          typeCounts[colNum][type.ordinal()]++;
+          newValues[colNum] = values[colNum];
+        }else{
+          newValues[colNum] = null;
+        }
+      }
+
+      previewRows.add(new Row(newValues));
+
+      numberOfRows--;
+      if (numberOfRows <= 0 || !iterator().hasNext())
+        break;
+
+      r = iterator().next();
+    }
+
+    if (previewRows.size() <= 0)
+      throw new NoSuchElementException("Does not contain any rows.");
+
+    header = new ArrayList<>(numOfCols);
+    for (int colNum = 0; colNum < numOfCols; colNum++) {
+      int dataTypeId = getLikelyDataType(typeCounts, colNum);
+      ColumnDescription.DataTypes type = ColumnDescription.DataTypes.values()[dataTypeId];
+      String colName = "Column" + colNum;
+      if (null != headerRow)
+        colName = (String) headerRow.getRow()[colNum];
+
+      ColumnDescription cd = new ColumnDescriptionImpl(colName, type.toString(), colNum);
+      header.add(cd);
+    }
+
+    return new PreviewData(header,previewRows);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/PreviewData.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/PreviewData.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/PreviewData.java
new file mode 100644
index 0000000..b00e2fb
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/PreviewData.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers;
+
+import org.apache.ambari.view.hive2.client.ColumnDescription;
+import org.apache.ambari.view.hive2.client.Row;
+
+import java.util.List;
+
+/**
+ * Encapsulating preview data from parser.
+ */
+public class PreviewData {
+  private List<ColumnDescription> header;
+  private List<Row> previewRows;
+
+  public PreviewData() {
+  }
+
+  public PreviewData(List<ColumnDescription> header, List<Row> previewRows) {
+    this.header = header;
+    this.previewRows = previewRows;
+  }
+
+  public List<ColumnDescription> getHeader() {
+    return header;
+  }
+
+  public void setHeader(List<ColumnDescription> header) {
+    this.header = header;
+  }
+
+  public List<Row> getPreviewRows() {
+    return previewRows;
+  }
+
+  public void setPreviewRows(List<Row> previewRows) {
+    this.previewRows = previewRows;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/RowIterator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/RowIterator.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/RowIterator.java
new file mode 100644
index 0000000..747e7ff
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/RowIterator.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers;
+
+import org.apache.ambari.view.hive2.client.Row;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+
+/**
+ * Converts the Map of values created by JSON/XML Parser into ordered values in Row
+ * Takes RowMapIterator as input
+ */
+public class RowIterator implements Iterator<Row> {
+
+  private LinkedList<String> headers = null;
+  private RowMapIterator iterator;
+
+  /**
+   * creates a row iterator for the map values in RowMapIterator
+   * keeps the keys in map as header.
+   * @param iterator
+   */
+  public RowIterator(RowMapIterator iterator) {
+    this.iterator = iterator;
+    LinkedHashMap<String, String> obj = iterator.peek();
+    if (null != obj)
+      headers = new LinkedList<>(obj.keySet());
+  }
+
+  @Override
+  public boolean hasNext() {
+    return iterator.hasNext();
+  }
+
+
+  @Override
+  public Row next() {
+    LinkedHashMap<String, String> r = this.iterator.next();
+    if (null == r) {
+      return null;
+    }
+
+    return convertToRow(r);
+  }
+
+  @Override
+  public void remove() {
+    iterator.remove();
+  }
+
+  /**
+   * @return : ordered collection of string of headers
+   */
+  public LinkedList<String> extractHeaders() {
+    return headers;
+  }
+
+  /**
+   * converts the map into a Row
+   * @param lr
+   * @return
+   */
+  private Row convertToRow(LinkedHashMap<String, String> lr) {
+    Object[] data = new Object[headers.size()];
+    int i = 0;
+    for (String cd : headers) {
+      String d = lr.get(cd);
+
+      if (d != null)
+        d = d.trim(); // trim to remove any \n etc which is used as a separator for rows in TableDataReader
+
+      data[i++] = d;
+    }
+
+    return new Row(data);
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/RowMapIterator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/RowMapIterator.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/RowMapIterator.java
new file mode 100644
index 0000000..de13347
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/RowMapIterator.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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+
+/**
+ * iterator which generates Ordered Map of column name and values for each row from streams like JSON and XML
+ */
+public interface RowMapIterator extends Iterator<LinkedHashMap<String, String>> {
+  LinkedHashMap<String, String> peek() ;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/csv/CSVIterator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/csv/CSVIterator.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/csv/CSVIterator.java
new file mode 100644
index 0000000..c4abb99
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/csv/CSVIterator.java
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers.csv;
+
+import org.apache.ambari.view.hive2.client.Row;
+import org.apache.commons.csv.CSVRecord;
+
+import java.util.Iterator;
+
+/**
+ * iterates over the input CSV records and generates Row objects
+ */
+class CSVIterator implements Iterator<Row> {
+
+  private Iterator<CSVRecord> iterator;
+
+  public CSVIterator(Iterator<CSVRecord> iterator) {
+    this.iterator = iterator;
+  }
+
+  @Override
+  public boolean hasNext() {
+    return iterator.hasNext();
+  }
+
+  @Override
+  public Row next() {
+    CSVRecord row = iterator.next();
+    Object[] values = new Object[row.size()];
+    for (int i = 0; i < values.length; i++) {
+      values[i] = row.get(i);
+    }
+    Row r = new Row(values);
+    return r;
+  }
+
+  @Override
+  public void remove() {
+    this.iterator.remove();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/csv/CSVParser.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/csv/CSVParser.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/csv/CSVParser.java
new file mode 100644
index 0000000..74cc060
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/csv/CSVParser.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.view.hive2.resources.uploads.parsers.csv;
+
+import org.apache.ambari.view.hive2.client.Row;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.ParseOptions;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.Parser;
+import org.apache.commons.csv.CSVFormat;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Parses the given Reader which contains CSV stream and extracts headers and rows, and detect datatypes of columns
+ */
+public class CSVParser extends Parser {
+
+  private CSVIterator iterator;
+  private org.apache.commons.csv.CSVParser parser;
+
+  public CSVParser(Reader reader, ParseOptions parseOptions) throws IOException {
+    super(reader, parseOptions);
+    parser = new org.apache.commons.csv.CSVParser(this.reader, CSVFormat.EXCEL);
+    iterator = new CSVIterator(parser.iterator());
+  }
+
+  @Override
+  public Row extractHeader() {
+    return this.iterator().next();
+  }
+
+  @Override
+  public void close() throws IOException {
+    this.parser.close();
+  }
+
+  public Iterator<Row> iterator() {
+    return iterator; // only one iterator per parser.
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/json/JSONIterator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/json/JSONIterator.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/json/JSONIterator.java
new file mode 100644
index 0000000..54aa0a9
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/json/JSONIterator.java
@@ -0,0 +1,160 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers.json;
+
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.EndOfDocumentException;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.RowMapIterator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.LinkedHashMap;
+
+/**
+ * iterates over the JsonReader and reads creates row data
+ * assumes the array of json objects.
+ * eg : [ { "col1Name" : "value-1-1", "col2Name" : "value-1-2"}, { "col1Name" : "value-2-1", "col2Name" : "value-2-2"}]
+ */
+class JSONIterator implements RowMapIterator {
+
+  protected final static Logger LOG =
+          LoggerFactory.getLogger(JSONIterator.class);
+
+  private LinkedHashMap<String, String> nextObject = null;
+
+  private LinkedHashMap<String, String> readNextObject(JsonReader reader) throws IOException, EndOfDocumentException {
+    LinkedHashMap<String, String> row = new LinkedHashMap<>();
+    boolean objectStarted = false;
+    boolean shouldBeName = false;
+    String currentName = null;
+
+    while (true) {
+      JsonToken token = reader.peek();
+      switch (token) {
+        case BEGIN_ARRAY:
+          throw new IllegalArgumentException("Row data cannot have an array.");
+        case END_ARRAY:
+          throw new EndOfDocumentException("End of Json Array document.");
+        case BEGIN_OBJECT:
+          if (objectStarted == true) {
+            throw new IllegalArgumentException("Nested objects not supported.");
+          }
+          if (shouldBeName == true) {
+            throw new IllegalArgumentException("name expected, got begin_object");
+          }
+          objectStarted = true;
+          shouldBeName = true;
+          reader.beginObject();
+          break;
+        case END_OBJECT:
+          if (shouldBeName == false) {
+            throw new IllegalArgumentException("value expected, got end_object");
+          }
+          reader.endObject();
+          return row;
+        case NAME:
+          if (shouldBeName == false) {
+            throw new IllegalArgumentException("name not expected at this point.");
+          }
+          shouldBeName = false;
+          currentName = reader.nextName();
+          break;
+        case NUMBER:
+        case STRING:
+          if (shouldBeName == true) {
+            throw new IllegalArgumentException("value not expected at this point.");
+          }
+          String n = reader.nextString();
+          row.put(currentName, n);
+          shouldBeName = true;
+          break;
+        case BOOLEAN:
+          if (shouldBeName == true) {
+            throw new IllegalArgumentException("value not expected at this point.");
+          }
+          String b = String.valueOf(reader.nextBoolean());
+          row.put(currentName, b);
+          shouldBeName = true;
+          break;
+        case NULL:
+          if (shouldBeName == true) {
+            throw new IllegalArgumentException("value not expected at this point.");
+          }
+          reader.nextNull();
+          row.put(currentName, "");
+          shouldBeName = true;
+          break;
+        case END_DOCUMENT:
+          return row;
+
+        default:
+          throw new IllegalArgumentException("Illegal token detected inside json: token : " + token.toString());
+      }
+    }
+  }
+
+  private JsonReader reader;
+
+  public JSONIterator(JsonReader reader) throws IOException {
+    this.reader = reader;
+    // test the start of array
+    JsonToken jt = reader.peek();
+    if (jt != JsonToken.BEGIN_ARRAY) {
+      throw new IllegalArgumentException("Expected the whole document to contain a single JsonArray.");
+    }
+
+    reader.beginArray(); // read the start of array
+    try {
+      nextObject = readNextObject(this.reader);
+    } catch (EndOfDocumentException e) {
+    }
+  }
+
+  @Override
+  public boolean hasNext() {
+    return null != nextObject;
+  }
+
+  public LinkedHashMap<String, String> peek() {
+    return nextObject;
+  }
+
+  @Override
+  public LinkedHashMap<String, String> next() {
+    LinkedHashMap<String, String> currObject = nextObject;
+    try {
+      nextObject = readNextObject(this.reader);
+    } catch (EndOfDocumentException e) {
+      LOG.debug("End of Json document reached with next character ending the JSON Array.");
+      nextObject = null;
+    } catch (Exception e){
+      // for any other exception throw error right away
+      throw new IllegalArgumentException(e);
+    }
+    return currObject;
+  }
+
+  @Override
+  public void remove() {
+    // no operation.
+    LOG.info("No operation when remove called on JSONIterator.");
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/json/JSONParser.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/json/JSONParser.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/json/JSONParser.java
new file mode 100644
index 0000000..772b6fd
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/json/JSONParser.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers.json;
+
+import com.google.gson.stream.JsonReader;
+import org.apache.ambari.view.hive2.client.Row;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.ParseOptions;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.Parser;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.RowIterator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Collection;
+import java.util.Iterator;
+
+
+/**
+ * Parses the input data from reader as JSON and provides iterator for rows.
+ *
+ * Expects the input reader to contains a JsonArray in which each element is a JsonObject
+ * corresponding to the row.
+ * eg. :
+ *
+ * [
+ *  {row1-col1, row1-col2, row1-col3},
+ *  {row2-col1, row2-col2, row2-col3}
+ * ]
+ *
+ */
+public class JSONParser extends Parser {
+
+  protected final static Logger LOG =
+          LoggerFactory.getLogger(JSONParser.class);
+
+  private RowIterator iterator;
+  private JsonReader jsonReader;
+  private JSONIterator JSONIterator;
+
+  public JSONParser(Reader reader, ParseOptions parseOptions) throws IOException {
+    super(reader, parseOptions);
+    this.jsonReader = new JsonReader(this.reader);
+    JSONIterator = new JSONIterator(this.jsonReader);
+    iterator = new RowIterator(JSONIterator);
+  }
+
+  @Override
+  public Row extractHeader() {
+    Collection<String> headers = this.iterator.extractHeaders();
+    Object[] objs = new Object[headers.size()];
+    Iterator<String> iterator = headers.iterator();
+    for(int i = 0 ; i < headers.size() ; i++){
+      objs[i] = iterator.next();
+    }
+
+    return new Row(objs);
+  }
+
+  @Override
+  public void close() throws IOException {
+    this.jsonReader.close();
+  }
+
+  @Override
+  public Iterator<Row> iterator() {
+    return iterator;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/xml/XMLIterator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/xml/XMLIterator.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/xml/XMLIterator.java
new file mode 100644
index 0000000..6b43735
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/xml/XMLIterator.java
@@ -0,0 +1,195 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers.xml;
+
+import org.apache.ambari.view.hive2.resources.uploads.parsers.EndOfDocumentException;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.RowMapIterator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.*;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+
+/**
+ * assumes XML of following format
+ * <table>
+ * <row>
+ * <col name="col1Name">row1-col1-Data</col>
+ * <col name="col2Name">row1-col2-Data</col>
+ * <col name="col3Name">row1-col3-Data</col>
+ * <col name="col4Name">row1-col4-Data</col>
+ * </row>
+ * <row>
+ * <col name="col1Name">row2-col1-Data</col>
+ * <col name="col2Name">row2-col2-Data</col>
+ * <col name="col3Name">row2-col3-Data</col>
+ * <col name="col4Name">row2-col4-Data</col>
+ * </row>
+ * </table>
+ */
+class XMLIterator implements RowMapIterator {
+
+  protected final static Logger LOG =
+          LoggerFactory.getLogger(XMLIterator.class);
+
+  private LinkedHashMap<String, String> nextObject = null;
+  private static final String TAG_TABLE = "table";
+  private static final String TAG_ROW = "row";
+  private static final String TAG_COL = "col";
+  private boolean documentStarted = false;
+  private XMLEventReader reader;
+
+  public XMLIterator(XMLEventReader reader) throws IOException {
+    this.reader = reader;
+    try {
+      nextObject = readNextObject(this.reader);
+    } catch (EndOfDocumentException e) {
+      LOG.debug("error : {}", e);
+    } catch (XMLStreamException e) {
+      throw new IOException(e);
+    }
+  }
+
+  @Override
+  public boolean hasNext() {
+    return null != nextObject;
+  }
+
+  public LinkedHashMap<String, String> peek() {
+    return nextObject;
+  }
+
+  @Override
+  public LinkedHashMap<String, String> next() {
+    LinkedHashMap<String, String> currObject = nextObject;
+    try {
+      nextObject = readNextObject(this.reader);
+    } catch (IOException e) {
+      LOG.error("Exception occured while reading the next row from XML : {} ", e);
+      nextObject = null;
+    } catch (EndOfDocumentException e) {
+      LOG.debug("End of XML document reached with next character ending the XML.");
+      nextObject = null;
+    } catch (XMLStreamException e) {
+      LOG.error("Exception occured while reading the next row from XML : {} ", e);
+      nextObject = null;
+    }
+    return currObject;
+  }
+
+  @Override
+  public void remove() {
+    // no operation.
+    LOG.info("No operation when remove called.");
+  }
+
+  private LinkedHashMap<String, String> readNextObject(XMLEventReader reader) throws IOException, EndOfDocumentException, XMLStreamException {
+    LinkedHashMap<String, String> row = new LinkedHashMap<>();
+    boolean objectStarted = false;
+    String currentName = null;
+
+    while (true) {
+      XMLEvent event = reader.nextEvent();
+      switch (event.getEventType()) {
+        case XMLStreamConstants.START_ELEMENT:
+          StartElement startElement = event.asStartElement();
+          String qName = startElement.getName().getLocalPart();
+          LOG.debug("startName : {}" , qName);
+          switch (qName) {
+            case TAG_TABLE:
+              if (documentStarted) {
+                throw new IllegalArgumentException("Cannot have a <table> tag nested inside another <table> tag");
+              } else {
+                documentStarted = true;
+              }
+              break;
+            case TAG_ROW:
+              if (objectStarted) {
+                throw new IllegalArgumentException("Cannot have a <row> tag nested inside another <row> tag");
+              } else {
+                objectStarted = true;
+              }
+              break;
+            case TAG_COL:
+              if (!objectStarted) {
+                throw new IllegalArgumentException("Stray tag " + qName);
+              }
+              Attribute nameAttr = startElement.getAttributeByName( new QName("name"));
+              if( null == nameAttr ){
+                throw new IllegalArgumentException("Missing name attribute in col tag.");
+              }
+              currentName = nameAttr.getValue();
+              break;
+            default:
+              throw new IllegalArgumentException("Illegal start tag " + qName + " encountered.");
+          }
+          break;
+        case XMLStreamConstants.END_ELEMENT:
+          EndElement endElement = event.asEndElement();
+          String name = endElement.getName().getLocalPart();
+          LOG.debug("endName : {}", name);
+          switch (name) {
+            case TAG_TABLE:
+              if (!documentStarted) {
+                throw new IllegalArgumentException("Stray </table> tag.");
+              }
+              throw new EndOfDocumentException("End of XML document.");
+
+            case TAG_ROW:
+              if (!objectStarted) {
+                throw new IllegalArgumentException("Stray </row> tag.");
+              }
+              return row;
+
+            case TAG_COL:
+              if (!objectStarted) {
+                throw new IllegalArgumentException("Stray tag " + name);
+              }
+              currentName = null;
+              break;
+
+            default:
+              throw new IllegalArgumentException("Illegal start ending " + name + " encountered.");
+          }
+          break;
+        case XMLStreamConstants.CHARACTERS:
+          Characters characters = event.asCharacters();
+          if (characters.isWhiteSpace() && currentName == null)
+            break;
+          String data = characters.getData();
+          LOG.debug("character data : {}", data);
+          if (currentName == null) {
+            throw new IllegalArgumentException("Illegal characters outside any tag : " + data);
+          } else {
+            String oldData = row.get(currentName);
+            if (null != oldData) {
+              data = oldData + data;
+            }
+            row.put(currentName, data);
+          }
+          break;
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/xml/XMLParser.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/xml/XMLParser.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/xml/XMLParser.java
new file mode 100644
index 0000000..51671e5
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/xml/XMLParser.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers.xml;
+
+import org.apache.ambari.view.hive2.client.Row;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.ParseOptions;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.Parser;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.RowIterator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * assumes XML of following format
+ * <table>
+ * <row>
+ * <col name="col1Name">row1-col1-Data</col>
+ * <col name="col2Name">row1-col2-Data</col>
+ * <col name="col3Name">row1-col3-Data</col>
+ * <col name="col4Name">row1-col4-Data</col>
+ * </row>
+ * <row>
+ * <col name="col1Name">row2-col1-Data</col>
+ * <col name="col2Name">row2-col2-Data</col>
+ * <col name="col3Name">row2-col3-Data</col>
+ * <col name="col4Name">row2-col4-Data</col>
+ * </row>
+ * </table>
+ */
+public class XMLParser extends Parser {
+
+  protected final static Logger LOG =
+          LoggerFactory.getLogger(XMLParser.class);
+
+  private RowIterator iterator;
+  private XMLEventReader xmlReader;
+  private XMLIterator xmlIterator;
+
+  public XMLParser(Reader reader, ParseOptions parseOptions) throws IOException {
+    super(reader, parseOptions);
+    XMLInputFactory factory = XMLInputFactory.newInstance();
+    try {
+      this.xmlReader = factory.createXMLEventReader(reader);
+    } catch (XMLStreamException e) {
+      LOG.error("error occurred while creating xml reader : ", e);
+      throw new IOException("error occurred while creating xml reader : ", e);
+    }
+    xmlIterator = new XMLIterator(this.xmlReader);
+    iterator = new RowIterator(xmlIterator);
+  }
+
+  @Override
+  public Row extractHeader() {
+    Collection<String> headers = this.iterator.extractHeaders();
+    Object[] objs = new Object[headers.size()];
+    Iterator<String> iterator = headers.iterator();
+    for (int i = 0; i < headers.size(); i++) {
+      objs[i] = iterator.next();
+    }
+
+    return new Row(objs);
+  }
+
+  @Override
+  public void close() throws IOException {
+    try {
+      this.xmlReader.close();
+    } catch (XMLStreamException e) {
+      throw new IOException(e);
+    }
+  }
+
+  @Override
+  public Iterator<Row> iterator() {
+    return iterator;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/DeleteQueryInput.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/DeleteQueryInput.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/DeleteQueryInput.java
new file mode 100644
index 0000000..dde5704
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/DeleteQueryInput.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.query;
+
+public class DeleteQueryInput {
+  private String database;
+  private String table;
+
+  public DeleteQueryInput() {
+  }
+
+  public DeleteQueryInput(String database, String table) {
+    this.database = database;
+    this.table = table;
+  }
+
+  public String getDatabase() {
+    return database;
+  }
+
+  public void setDatabase(String database) {
+    this.database = database;
+  }
+
+  public String getTable() {
+    return table;
+  }
+
+  public void setTable(String table) {
+    this.table = table;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/InsertFromQueryInput.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/InsertFromQueryInput.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/InsertFromQueryInput.java
new file mode 100644
index 0000000..22dec67
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/InsertFromQueryInput.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.query;
+
+public class InsertFromQueryInput {
+  private String fromDatabase;
+  private String fromTable;
+  private String toDatabase;
+  private String toTable;
+
+  public InsertFromQueryInput() {
+  }
+
+  public InsertFromQueryInput(String fromDatabase, String fromTable, String toDatabase, String toTable) {
+    this.fromDatabase = fromDatabase;
+    this.fromTable = fromTable;
+    this.toDatabase = toDatabase;
+    this.toTable = toTable;
+  }
+
+  public String getFromDatabase() {
+    return fromDatabase;
+  }
+
+  public void setFromDatabase(String fromDatabase) {
+    this.fromDatabase = fromDatabase;
+  }
+
+  public String getFromTable() {
+    return fromTable;
+  }
+
+  public void setFromTable(String fromTable) {
+    this.fromTable = fromTable;
+  }
+
+  public String getToDatabase() {
+    return toDatabase;
+  }
+
+  public void setToDatabase(String toDatabase) {
+    this.toDatabase = toDatabase;
+  }
+
+  public String getToTable() {
+    return toTable;
+  }
+
+  public void setToTable(String toTable) {
+    this.toTable = toTable;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/LoadQueryInput.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/LoadQueryInput.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/LoadQueryInput.java
new file mode 100644
index 0000000..6ce705d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/LoadQueryInput.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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.query;
+
+/**
+ * input for QueryGenerator for generating Load From Query
+ */
+public class LoadQueryInput {
+  private String hdfsFilePath;
+  private String databaseName;
+  private String tableName;
+
+  public LoadQueryInput(String hdfsFilePath, String databaseName, String tableName) {
+    this.hdfsFilePath = hdfsFilePath;
+    this.databaseName = databaseName;
+    this.tableName = tableName;
+  }
+
+  public String getHdfsFilePath() {
+    return hdfsFilePath;
+  }
+
+  public void setHdfsFilePath(String hdfsFilePath) {
+    this.hdfsFilePath = hdfsFilePath;
+  }
+
+  public String getDatabaseName() {
+    return databaseName;
+  }
+
+  public void setDatabaseName(String databaseName) {
+    this.databaseName = databaseName;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public void setTableName(String tableName) {
+    this.tableName = tableName;
+  }
+
+  @Override
+  public String toString() {
+    return "LoadQueryInput{" +
+            "hdfsFilePath='" + hdfsFilePath + '\'' +
+            ", databaseName='" + databaseName + '\'' +
+            ", tableName='" + tableName + '\'' +
+            '}';
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/QueryGenerator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/QueryGenerator.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/QueryGenerator.java
new file mode 100644
index 0000000..a9bc2b9
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/QueryGenerator.java
@@ -0,0 +1,98 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.query;
+
+import org.apache.ambari.view.hive2.client.ColumnDescription;
+import org.apache.ambari.view.hive2.resources.uploads.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * generates the sql query from given data
+ */
+public class QueryGenerator {
+  protected final static Logger LOG =
+          LoggerFactory.getLogger(QueryGenerator.class);
+
+  public String generateCreateQuery(TableInfo tableInfo) {
+    String tableName = tableInfo.getTableName();
+    List<ColumnDescriptionImpl> cdList = tableInfo.getColumns();
+
+    StringBuilder query = new StringBuilder();
+    query.append("create table " + tableName + " (");
+    Collections.sort(cdList, new Comparator<ColumnDescription>() {
+      @Override
+      public int compare(ColumnDescription o1, ColumnDescription o2) {
+        return o1.getPosition() - o2.getPosition();
+      }
+    });
+
+    boolean first = true;
+    for (ColumnDescriptionImpl cd : cdList) {
+      if (first) {
+        first = false;
+      } else {
+        query.append(", ");
+      }
+
+      query.append(cd.getName() + " " + cd.getType());
+      if (cd.getPrecision() != null) {
+        query.append("(").append(cd.getPrecision());
+        if (cd.getScale() != null) {
+          query.append(",").append(cd.getScale());
+        }
+        query.append(")");
+      }
+
+    }
+
+    query.append(")");
+
+    if (tableInfo.getHiveFileType() == HiveFileType.TEXTFILE)
+      query.append(" ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' STORED AS TEXTFILE;");
+    else
+      query.append(" STORED AS " + tableInfo.getHiveFileType() + ";");
+
+    String queryString = query.toString();
+    LOG.info("Query : {}", queryString);
+    return queryString;
+  }
+
+  public String generateInsertFromQuery(InsertFromQueryInput ifqi) {
+    String insertQuery = "insert into table " + ifqi.getToDatabase() + "." + ifqi.getToTable() + " select * from " + ifqi.getFromDatabase() + "." + ifqi.getFromTable();
+    LOG.info("Insert Query : {}", insertQuery);
+    return insertQuery;
+  }
+
+  public String generateDropTableQuery(DeleteQueryInput deleteQueryInput) {
+    String dropQuery = "drop table " + deleteQueryInput.getDatabase() + "." + deleteQueryInput.getTable();
+    LOG.info("Drop Query : {}", dropQuery);
+    return dropQuery;
+  }
+
+  public String generateLoadQuery(LoadQueryInput loadQueryInput) {
+    String loadFromQuery = "LOAD DATA INPATH '"  + loadQueryInput.getHdfsFilePath() + "' INTO TABLE " + loadQueryInput.getDatabaseName() + "." + loadQueryInput.getTableName() + ";" ;
+    LOG.info("Load From Query : {}", loadFromQuery);
+    return loadFromQuery;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/TableInfo.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/TableInfo.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/TableInfo.java
new file mode 100644
index 0000000..2b91d7b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/query/TableInfo.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.query;
+
+import org.apache.ambari.view.hive2.resources.uploads.ColumnDescriptionImpl;
+import org.apache.ambari.view.hive2.resources.uploads.HiveFileType;
+
+import java.util.List;
+
+/**
+ * used as input in Query generation
+ */
+public class TableInfo {
+  private String tableName;
+  private String databaseName;
+  private List<ColumnDescriptionImpl> columns;
+  private HiveFileType hiveFileType;
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public void setTableName(String tableName) {
+    this.tableName = tableName;
+  }
+
+  public String getDatabaseName() {
+    return databaseName;
+  }
+
+  public void setDatabaseName(String databaseName) {
+    this.databaseName = databaseName;
+  }
+
+  public List<ColumnDescriptionImpl> getColumns() {
+    return columns;
+  }
+
+  public void setColumns(List<ColumnDescriptionImpl> columns) {
+    this.columns = columns;
+  }
+
+  public HiveFileType getHiveFileType() {
+    return hiveFileType;
+  }
+
+  public void setHiveFileType(HiveFileType hiveFileType) {
+    this.hiveFileType = hiveFileType;
+  }
+
+  public TableInfo(String databaseName, String tableName, List<ColumnDescriptionImpl> columns, HiveFileType hiveFileType) {
+    this.tableName = tableName;
+    this.databaseName = databaseName;
+    this.columns = columns;
+    this.hiveFileType = hiveFileType;
+  }
+
+  public TableInfo(TableInfo tableInfo) {
+    this.tableName = tableInfo.tableName;
+    this.databaseName = tableInfo.databaseName;
+    this.columns = tableInfo.columns;
+    this.hiveFileType = tableInfo.hiveFileType;
+  }
+
+  public TableInfo() {
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/BadRequestFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/BadRequestFormattedException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/BadRequestFormattedException.java
new file mode 100644
index 0000000..cf56be2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/BadRequestFormattedException.java
@@ -0,0 +1,27 @@
+/**
+ * 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.ambari.view.hive2.utils;
+
+public class BadRequestFormattedException extends ServiceFormattedException {
+  private final static int STATUS = 400;
+
+  public BadRequestFormattedException(String message, Throwable exception) {
+    super(message, exception, STATUS);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/FilePaginator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/FilePaginator.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/FilePaginator.java
new file mode 100644
index 0000000..cf30f55
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/FilePaginator.java
@@ -0,0 +1,127 @@
+/**
+ * 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.ambari.view.hive2.utils;
+
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.hadoop.fs.FSDataInputStream;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+import static java.lang.Math.ceil;
+
+/**
+ * Pagination for HDFS file implementation
+ */
+public class FilePaginator {
+  public static int MB = 1024*1024;
+  public static int PAGE_SIZE = 1*MB;
+
+  private String filePath;
+  private HdfsApi hdfsApi;
+
+  /**
+   * Constructor
+   * @param filePath Path to file on HDFS
+   * @param hdfsApi hdfs api
+   */
+  public FilePaginator(String filePath, HdfsApi hdfsApi) {
+    this.filePath = filePath;
+    this.hdfsApi = hdfsApi;
+  }
+
+  /**
+   * Set page size
+   * @param PAGE_SIZE size
+   */
+  public static void setPageSize(int PAGE_SIZE) {
+    FilePaginator.PAGE_SIZE = PAGE_SIZE;
+  }
+
+  /**
+   * Get page count
+   * @return page count
+   * @throws java.io.IOException
+   * @throws InterruptedException
+   */
+  public long pageCount() throws IOException, InterruptedException {
+    return (long)
+        ceil( hdfsApi.getFileStatus(filePath).getLen() / ((double)PAGE_SIZE) );
+  }
+
+  /**
+   * Read one page of size PAGE_SIZE
+   * @param page page index
+   * @return data in UTF-8
+   * @throws java.io.IOException
+   * @throws InterruptedException
+   */
+  public String readPage(long page) throws IOException, InterruptedException {
+    FSDataInputStream stream = hdfsApi.open(filePath);
+    try {
+      stream.seek(page * PAGE_SIZE);
+    } catch (IOException e) {
+      throw new IllegalArgumentException("Page " + page + " does not exists");
+    }
+
+    byte[] buffer = new byte[PAGE_SIZE];
+    int readCount = 0;
+    int read = 0;
+    while(read < PAGE_SIZE) {
+      try {
+        readCount = stream.read(buffer, read, PAGE_SIZE-read);
+      } catch (IOException e) {
+        stream.close();
+        throw e;
+      }
+      if (readCount == -1)
+        break;
+      read += readCount;
+    }
+    if (read != 0) {
+      byte[] readData = Arrays.copyOfRange(buffer, 0, read);
+      return new String(readData, Charset.forName("UTF-8"));
+    } else {
+      if (page == 0) {
+        return "";
+      }
+      throw new IllegalArgumentException("Page " + page + " does not exists");
+    }
+  }
+
+  public String readFull(long sizeLimit) throws IOException, InterruptedException {
+    StringBuilder builder = new StringBuilder();
+    int i = 0;
+    while (true) {
+      try {
+        builder.append(readPage(i++));
+      } catch (IllegalArgumentException ex) {
+        break;
+      }
+      if (sizeLimit != -1 && (i+1)*PAGE_SIZE > sizeLimit)
+        break;
+    }
+    return builder.toString();
+  }
+
+  public String readFull() throws IOException, InterruptedException {
+    return readFull(-1);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/HiveActorConfiguration.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/HiveActorConfiguration.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/HiveActorConfiguration.java
new file mode 100644
index 0000000..d6cb6e8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/HiveActorConfiguration.java
@@ -0,0 +1,71 @@
+/*
+ * 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.ambari.view.hive2.utils;
+
+import org.apache.ambari.view.ViewContext;
+
+/**
+ * This fetches the configuration for the actor system from ambari.properties
+ */
+public class HiveActorConfiguration {
+  private static String DEFAULT_CONFIG = "default";
+  private static String CONNECTION_PREFIX = "views.ambari.hive.";
+  private static String CONNECTION_INACTIVITY_TIMEOUT_PATTERN = CONNECTION_PREFIX + "%s.connection.inactivity.timeout";
+  private static String CONNECTION_TERMINATION_TIMEOUT_PATTERN = CONNECTION_PREFIX + "%s.connection.termination.timeout";
+  private static String SYNC_QUERY_TIMEOUT_PATTERN = CONNECTION_PREFIX + "%s.sync.query.timeout";
+  private static String RESULT_FETCH_TIMEOUT_PATTERN = CONNECTION_PREFIX + "%s.result.fetch.timeout";
+
+  private final ViewContext context;
+
+  public HiveActorConfiguration(ViewContext context) {
+    this.context = context;
+  }
+
+  public long getInactivityTimeout(long defaultValue) {
+    return Long.parseLong(getPropertiesFromContext(CONNECTION_INACTIVITY_TIMEOUT_PATTERN, String.valueOf(defaultValue)));
+  }
+
+  public long getTerminationTimeout(long defaultValue) {
+    return Long.parseLong(getPropertiesFromContext(CONNECTION_TERMINATION_TIMEOUT_PATTERN, String.valueOf(defaultValue)));
+  }
+
+  public long getSyncQueryTimeout(long defaultValue) {
+    return Long.parseLong(getPropertiesFromContext(SYNC_QUERY_TIMEOUT_PATTERN, String.valueOf(defaultValue)));
+  }
+
+  public long getResultFetchTimeout(long defaultValue) {
+    return Long.parseLong(getPropertiesFromContext(RESULT_FETCH_TIMEOUT_PATTERN, String.valueOf(defaultValue)));
+  }
+
+  /**
+   * Tries to get the specific configuration with the instance name. If not found then tries to
+   * find the default set in ambari.properties. If not found then returns the default value passed
+   * @param keyPattern Pattern used to generate ambari.properties key
+   * @param defaultValue Returned when the value is not found in ambari.properties
+   * @return value of the property
+   */
+  private String getPropertiesFromContext(String keyPattern, String defaultValue) {
+    String value;
+    value = context.getAmbariProperty(String.format(keyPattern, context.getInstanceName()));
+    if(value == null) {
+      value = context.getAmbariProperty(String.format(keyPattern, DEFAULT_CONFIG));
+    }
+    return value == null ? defaultValue: value;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/HiveClientFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/HiveClientFormattedException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/HiveClientFormattedException.java
new file mode 100644
index 0000000..3edadb2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/HiveClientFormattedException.java
@@ -0,0 +1,26 @@
+/**
+ * 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.ambari.view.hive2.utils;
+
+public class HiveClientFormattedException extends ServiceFormattedException {
+
+  public HiveClientFormattedException(Throwable exception) {
+    super(exception.getMessage(), exception);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/LoggingOutputStream.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/LoggingOutputStream.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/LoggingOutputStream.java
new file mode 100644
index 0000000..7695893
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/LoggingOutputStream.java
@@ -0,0 +1,85 @@
+/*
+ * 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.ambari.view.hive2.utils;
+
+import org.slf4j.Logger;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class LoggingOutputStream extends OutputStream {
+
+    private final ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
+    private final Logger logger;
+    private final LogLevel level;
+
+    public enum LogLevel {
+        TRACE, DEBUG, INFO, WARN, ERROR,
+    }
+
+    public LoggingOutputStream(Logger logger, LogLevel level) {
+        this.logger = logger;
+        this.level = level;
+    }
+
+    @Override
+    public void write(int b) {
+        if (b == '\n') {
+            String line = baos.toString();
+            baos.reset();
+
+            switch (level) {
+                case TRACE:
+                    logger.trace(line);
+                    break;
+                case DEBUG:
+                    logger.debug(line);
+                    break;
+                case ERROR:
+                    logger.error(line);
+                    break;
+                case INFO:
+                    logger.info(line);
+                    break;
+                case WARN:
+                    logger.warn(line);
+                    break;
+            }
+        } else {
+            baos.write(b);
+        }
+    }
+
+
+    /**
+     * Closes this output stream and releases any system resources
+     * associated with this stream. The general contract of <code>close</code>
+     * is that it closes the output stream. A closed stream cannot perform
+     * output operations and cannot be reopened.
+     * <p/>
+     * The <code>close</code> method of <code>OutputStream</code> does nothing.
+     *
+     * @throws IOException if an I/O error occurs.
+     */
+    @Override
+    public void close() throws IOException {
+        baos.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/MisconfigurationFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/MisconfigurationFormattedException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/MisconfigurationFormattedException.java
new file mode 100644
index 0000000..bee3fc1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/MisconfigurationFormattedException.java
@@ -0,0 +1,47 @@
+/**
+ * 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.ambari.view.hive2.utils;
+
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.HashMap;
+
+public class MisconfigurationFormattedException extends WebApplicationException {
+  private final static int STATUS = 500;
+  private final static String message = "Parameter \"%s\" is set to null";
+  private final static Logger LOG =
+      LoggerFactory.getLogger(MisconfigurationFormattedException.class);
+
+  public MisconfigurationFormattedException(String name) {
+    super(errorEntity(name));
+  }
+
+  protected static Response errorEntity(String name) {
+    HashMap<String, Object> response = new HashMap<String, Object>();
+    response.put("message", String.format(message, name));
+    response.put("trace", null);
+    response.put("status", STATUS);
+    return Response.status(STATUS).entity(new JSONObject(response)).type(MediaType.APPLICATION_JSON).build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/NotFoundFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/NotFoundFormattedException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/NotFoundFormattedException.java
new file mode 100644
index 0000000..b6b7dd0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/NotFoundFormattedException.java
@@ -0,0 +1,27 @@
+/**
+ * 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.ambari.view.hive2.utils;
+
+public class NotFoundFormattedException extends ServiceFormattedException {
+  private final static int STATUS = 404;
+
+  public NotFoundFormattedException(String message, Throwable exception) {
+    super(message, exception, STATUS);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/ServiceFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/ServiceFormattedException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/ServiceFormattedException.java
new file mode 100644
index 0000000..8c14bce
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/ServiceFormattedException.java
@@ -0,0 +1,105 @@
+/**
+ * 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.ambari.view.hive2.utils;
+
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.security.AccessControlException;
+import java.util.HashMap;
+
+public class ServiceFormattedException extends WebApplicationException {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(ServiceFormattedException.class);
+
+  public ServiceFormattedException(String message) {
+    super(errorEntity(message, null, suggestStatus(null), null));
+  }
+
+  public ServiceFormattedException(Throwable exception) {
+    super(errorEntity(null, exception, suggestStatus(exception), null));
+  }
+
+  public ServiceFormattedException(String message, Throwable exception) {
+    super(errorEntity(message, exception, suggestStatus(exception), null));
+  }
+
+  public ServiceFormattedException(String message, Throwable exception, int status) {
+    super(errorEntity(message, exception, status, null));
+  }
+
+  public ServiceFormattedException(String message, Exception ex, String curl) {
+    super(errorEntity(message, ex, suggestStatus(ex), curl));
+  }
+
+  private static int suggestStatus(Throwable exception) {
+    int status = 500;
+    if (exception == null) {
+      return status;
+    }
+    if (exception instanceof AccessControlException) {
+      status = 403;
+    }
+    /*if (exception instanceof HiveInvalidQueryException) {
+      status = 400;
+    }*/
+    return status;
+  }
+
+  protected static Response errorEntity(String message, Throwable e, int status, String header) {
+    HashMap<String, Object> response = new HashMap<String, Object>();
+
+    String trace = null;
+
+    response.put("message", message);
+    if (e != null) {
+      trace = e.toString() + "\n\n";
+      StringWriter sw = new StringWriter();
+      e.printStackTrace(new PrintWriter(sw));
+      trace += sw.toString();
+
+      if (message == null) {
+        String innerMessage = e.getMessage();
+        String autoMessage;
+
+        if (innerMessage != null)
+          autoMessage = String.format("E090 %s [%s]", innerMessage, e.getClass().getSimpleName());
+        else
+          autoMessage = "E090 " + e.getClass().getSimpleName();
+        response.put("message", autoMessage);
+      }
+    }
+    response.put("trace", trace);
+    response.put("status", status);
+
+    if(message != null && status != 400) LOG.error(message);
+    if(trace != null && status != 400) LOG.error(trace);
+
+    Response.ResponseBuilder responseBuilder = Response.status(status).entity(new JSONObject(response)).type(MediaType.APPLICATION_JSON);
+    if (header != null)
+      responseBuilder.header("X-INFO", header);
+    return responseBuilder.build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/SharedObjectsFactory.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/SharedObjectsFactory.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/SharedObjectsFactory.java
new file mode 100644
index 0000000..dd0b715
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/utils/SharedObjectsFactory.java
@@ -0,0 +1,185 @@
+/**
+ * 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.ambari.view.hive2.utils;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.IStorageFactory;
+import org.apache.ambari.view.hive2.persistence.Storage;
+import org.apache.ambari.view.hive2.persistence.utils.StorageFactory;
+import org.apache.ambari.view.hive2.resources.jobs.atsJobs.ATSParser;
+import org.apache.ambari.view.hive2.resources.jobs.atsJobs.ATSParserFactory;
+import org.apache.ambari.view.hive2.resources.jobs.rm.RMParser;
+import org.apache.ambari.view.hive2.resources.jobs.rm.RMParserFactory;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.IJobControllerFactory;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobControllerFactory;
+import org.apache.ambari.view.hive2.resources.savedQueries.SavedQueryResourceManager;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.ambari.view.utils.hdfs.HdfsApiException;
+import org.apache.ambari.view.utils.hdfs.HdfsUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Generates shared connections. Clients with same tag will get the same connection.
+ * e.g. user 'admin' using view instance 'HIVE1' will use one connection, another user
+ * will use different connection.
+ */
+public class SharedObjectsFactory implements IStorageFactory {
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(SharedObjectsFactory.class);
+
+  private ViewContext context;
+  private final IStorageFactory storageFactory;
+  private final ATSParserFactory atsParserFactory;
+  private final RMParserFactory rmParserFactory;
+
+  private static final Map<Class, Map<String, Object>> localObjects = new ConcurrentHashMap<Class, Map<String, Object>>();
+
+  public SharedObjectsFactory(ViewContext context) {
+    this.context = context;
+    this.storageFactory = new StorageFactory(context);
+    this.atsParserFactory = new ATSParserFactory(context);
+    this.rmParserFactory = new RMParserFactory(context);
+
+    synchronized (localObjects) {
+      if (localObjects.size() == 0) {
+        //localObjects.put(OperationHandleControllerFactory.class, new ConcurrentHashMap<String, Object>());
+        localObjects.put(Storage.class, new ConcurrentHashMap<String, Object>());
+        localObjects.put(IJobControllerFactory.class, new ConcurrentHashMap<String, Object>());
+        localObjects.put(ATSParser.class, new ConcurrentHashMap<String, Object>());
+        localObjects.put(SavedQueryResourceManager.class, new ConcurrentHashMap<String, Object>());
+        localObjects.put(HdfsApi.class, new ConcurrentHashMap<String, Object>());
+        localObjects.put(RMParser.class, new ConcurrentHashMap<String, Object>());
+      }
+    }
+  }
+
+  // =============================
+
+  /*public OperationHandleControllerFactory getOperationHandleControllerFactory() {
+    if (!localObjects.get(OperationHandleControllerFactory.class).containsKey(getTagName()))
+      localObjects.get(OperationHandleControllerFactory.class).put(getTagName(), new OperationHandleControllerFactory(context, this));
+    return (OperationHandleControllerFactory) localObjects.get(OperationHandleControllerFactory.class).get(getTagName());
+  }*/
+
+  // =============================
+  @Override
+  public Storage getStorage() {
+    if (!localObjects.get(Storage.class).containsKey(getTagName()))
+      localObjects.get(Storage.class).put(getTagName(), storageFactory.getStorage());
+    return (Storage) localObjects.get(Storage.class).get(getTagName());
+  }
+
+  // =============================
+  public IJobControllerFactory getJobControllerFactory() {
+    if (!localObjects.get(IJobControllerFactory.class).containsKey(getTagName()))
+      localObjects.get(IJobControllerFactory.class).put(getTagName(), new JobControllerFactory(context, this));
+    return (IJobControllerFactory) localObjects.get(IJobControllerFactory.class).get(getTagName());
+  }
+
+  // =============================
+
+  public SavedQueryResourceManager getSavedQueryResourceManager() {
+    if (!localObjects.get(SavedQueryResourceManager.class).containsKey(getTagName()))
+      localObjects.get(SavedQueryResourceManager.class).put(getTagName(), new SavedQueryResourceManager(context, this));
+    return (SavedQueryResourceManager) localObjects.get(SavedQueryResourceManager.class).get(getTagName());
+  }
+
+  // =============================
+  public ATSParser getATSParser() {
+    if (!localObjects.get(ATSParser.class).containsKey(getTagName()))
+      localObjects.get(ATSParser.class).put(getTagName(), atsParserFactory.getATSParser());
+    return (ATSParser) localObjects.get(ATSParser.class).get(getTagName());
+  }
+
+  // =============================
+  public RMParser getRMParser() {
+    if (!localObjects.get(RMParser.class).containsKey(getTagName()))
+      localObjects.get(RMParser.class).put(getTagName(), rmParserFactory.getRMParser());
+    return (RMParser) localObjects.get(RMParser.class).get(getTagName());
+  }
+
+  // =============================
+  public HdfsApi getHdfsApi() {
+    if (!localObjects.get(HdfsApi.class).containsKey(getTagName())) {
+      try {
+        localObjects.get(HdfsApi.class).put(getTagName(), HdfsUtil.connectToHDFSApi(context));
+      } catch (HdfsApiException e) {
+        String message = "F060 Couldn't open connection to HDFS";
+        LOG.error(message);
+        throw new ServiceFormattedException(message, e);
+      }
+    }
+    return (HdfsApi) localObjects.get(HdfsApi.class).get(getTagName());
+  }
+
+  /**
+   * Generates tag name. Clients with same tag will share one connection.
+   * @return tag name
+   */
+  public String getTagName() {
+    if (context == null)
+      return "<null>";
+    return String.format("%s:%s", context.getInstanceName(), context.getUsername());
+  }
+
+  /**
+   * For testing purposes, ability to substitute some local object
+   */
+  public void setInstance(Class clazz, Object object) {
+    localObjects.get(clazz).put(getTagName(), object);
+  }
+
+  /**
+   * For testing purposes, ability to clear all local objects of particular class
+   */
+  public void clear(Class clazz) {
+    localObjects.get(clazz).clear();
+  }
+
+  /**
+   * For testing purposes, ability to clear all connections
+   */
+  public void clear() {
+    for(Map<String, Object> map : localObjects.values()) {
+      map.clear();
+    }
+  }
+
+  /**
+   *
+   * Drops all objects for give instance name.
+   *
+   * @param instanceName
+   */
+  public static void dropInstanceCache(String instanceName){
+    for(Map<String,Object> cache : localObjects.values()){
+      for(Iterator<Map.Entry<String, Object>> it = cache.entrySet().iterator(); it.hasNext();){
+        Map.Entry<String, Object> entry = it.next();
+        if(entry.getKey().startsWith(instanceName+":")){
+          it.remove();
+        }
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/application.conf
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/application.conf b/contrib/views/hive-next/src/main/resources/application.conf
new file mode 100644
index 0000000..cb0cc7b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/application.conf
@@ -0,0 +1,57 @@
+#
+# Copyright 2011 The Apache Software Foundation
+#
+# 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.
+#
+
+akka {
+
+  # Log level used by the configured loggers (see "loggers") as soon
+  # as they have been started; before that, see "stdout-loglevel"
+  # Options: OFF, ERROR, WARNING, INFO, DEBUG
+  loglevel = "DEBUG"
+
+  # Log level for the very basic logger activated during ActorSystem startup.
+  # This logger prints the log messages to stdout (System.out).
+  # Options: OFF, ERROR, WARNING, INFO, DEBUG
+  stdout-loglevel = "INFO"
+
+  actor {
+
+    # Dispatcher to be used for creating Jdbc Connector actors (sync/Async)
+    jdbc-connector-dispatcher {
+      fork-join-executor {
+        parallelism-factor = 5.0
+      }
+    }
+
+    # Dispatcher to be used for creating Resultset related actors
+    result-dispatcher {
+      fork-join-executor {
+        parallelism-factor = 10.0
+      }
+    }
+
+    # Dispatcher to be used for creating miscellaneous actors like logger, exceptionWriter etc
+    misc-dispatcher {
+      fork-join-executor {
+        parallelism-factor = 5.0
+      }
+    }
+  }
+
+}
\ No newline at end of file


[20/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/pom.xml b/contrib/views/hive-next/pom.xml
new file mode 100644
index 0000000..c571352
--- /dev/null
+++ b/contrib/views/hive-next/pom.xml
@@ -0,0 +1,369 @@
+<!--
+   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/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.ambari.contrib.views</groupId>
+  <artifactId>hive-jdbc</artifactId>
+  <version>2.0.0.0-SNAPSHOT</version>
+  <name>Hive Jdbc</name>
+
+  <parent>
+    <groupId>org.apache.ambari.contrib.views</groupId>
+    <artifactId>ambari-contrib-views</artifactId>
+    <version>2.4.0.0.0</version>
+  </parent>
+
+  <repositories>
+    <repository>
+      <id>repository.apache.org</id>
+      <name>Apache Snapshot repo</name>
+      <url>https://repository.apache.org/content/groups/snapshots</url>
+    </repository>
+  </repositories>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.jayway.jsonpath</groupId>
+      <artifactId>json-path</artifactId>
+      <version>2.0.0</version>
+    </dependency>
+      <dependency>
+      <groupId>com.google.inject</groupId>
+      <artifactId>guice</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey.contribs</groupId>
+      <artifactId>jersey-multipart</artifactId>
+      <version>1.18</version>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-client</artifactId>
+      <version>1.8</version>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-core</artifactId>
+      <version>1.18.1</version>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-json</artifactId>
+      <version>1.9</version>
+    </dependency>
+    <dependency>
+      <groupId>com.googlecode.json-simple</groupId>
+      <artifactId>json-simple</artifactId>
+      <version>1.1.1</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-configuration</groupId>
+      <artifactId>commons-configuration</artifactId>
+      <version>1.6</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-csv</artifactId>
+      <version>1.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-collections4</artifactId>
+      <version>4.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.ambari</groupId>
+      <artifactId>ambari-views</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+      <version>2.2.2</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <version>3.0.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>1.7.5</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <version>1.7.5</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-hdfs</artifactId>
+      <version>${hadoop.version}</version>
+        <exclusions>
+            <exclusion>
+                <groupId>tomcat</groupId>
+                <artifactId>jasper-runtime</artifactId>
+            </exclusion>
+        </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-common</artifactId>
+      <version>${hadoop.version}</version>
+        <exclusions>
+            <exclusion>
+                <groupId>tomcat</groupId>
+                <artifactId>jasper-runtime</artifactId>
+            </exclusion>
+        </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-mapreduce-client-common</artifactId>
+      <version>${hadoop.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-mapreduce-client-core</artifactId>
+      <version>${hadoop.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-yarn-client</artifactId>
+      <version>${hadoop.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.ws.rs</groupId>
+      <artifactId>javax.ws.rs-api</artifactId>
+      <version>2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hive</groupId>
+      <artifactId>hive-jdbc</artifactId>
+      <version>${hive-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-cli</groupId>
+      <artifactId>commons-cli</artifactId>
+      <version>1.2</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+      <version>2.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.thrift</groupId>
+      <artifactId>libthrift</artifactId>
+      <version>0.9.0</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-testkit_2.11</artifactId>
+      <version>2.3.15</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-minicluster</artifactId>
+      <version>${hadoop.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.ambari.contrib.views</groupId>
+      <artifactId>ambari-views-utils</artifactId>
+      <version>2.4.0.0.0</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-validator</groupId>
+      <artifactId>commons-validator</artifactId>
+      <version>1.4.0</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>2.4</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+      <version>4.5.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpcore</artifactId>
+      <version>4.4.3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-csv</artifactId>
+      <version>1.1</version>
+    </dependency>
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-actor_2.11</artifactId>
+      <version>2.3.15</version>
+    </dependency>
+  </dependencies>
+
+  <properties>
+    <ambari.dir>${project.parent.parent.parent.basedir}</ambari.dir>
+    <hive-version>2.1.0-SNAPSHOT</hive-version>
+    <ambari.version>1.3.0.0-SNAPSHOT</ambari.version>
+  </properties>
+  <build>
+    <plugins>
+
+      <!-- Building frontend -->
+      <plugin>
+        <groupId>com.github.eirslett</groupId>
+        <artifactId>frontend-maven-plugin</artifactId>
+        <version>0.0.16</version>
+        <configuration>
+          <nodeVersion>v0.12.2</nodeVersion>
+          <npmVersion>1.4.8</npmVersion>
+          <workingDirectory>src/main/resources/ui/hive-web/</workingDirectory>
+        </configuration>
+        <executions>
+          <execution>
+            <id>install node and npm</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>install-node-and-npm</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>npm install</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>npm</goal>
+            </goals>
+            <configuration>
+              <arguments>install --python="${project.basedir}/../src/main/unix/ambari-python-wrap" --unsafe-perm</arguments>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>exec-maven-plugin</artifactId>
+        <groupId>org.codehaus.mojo</groupId>
+        <version>1.3.2</version>
+        <executions>
+          <execution>
+            <id>Hive build</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <workingDirectory>${basedir}/src/main/resources/ui/hive-web</workingDirectory>
+              <executable>node/node</executable>
+              <arguments>
+                <argument>node_modules/.bin/ember</argument>
+                <argument>build</argument>
+              </arguments>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.1</version>
+        <configuration>
+          <source>1.7</source>
+          <target>1.7</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}/lib</outputDirectory>
+              <includeScope>runtime</includeScope>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+       <groupId>org.vafer</groupId>
+       <artifactId>jdeb</artifactId>
+       <version>1.0.1</version>
+       <executions>
+           <execution>
+               <phase>none</phase>
+               <goals>
+                   <goal>jdeb</goal>
+               </goals>
+           </execution>
+       </executions>
+       <configuration>
+           <submodules>false</submodules>
+       </configuration>
+     </plugin>
+    </plugins>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>false</filtering>
+        <includes>
+          <include>META-INF/**/*</include>
+          <include>view.xml</include>
+          <include>view.log4j.properties</include>
+          <include>application.conf</include>
+        </includes>
+      </resource>
+      <resource>
+        <directory>src/main/resources/ui/hive-web/dist</directory>
+        <filtering>false</filtering>
+      </resource>
+      <resource>
+        <directory>src/main/resources/ui/hive-web/bower_components/polestar</directory>
+        <filtering>false</filtering>
+        <targetPath>polestar</targetPath>
+      </resource>
+      <resource>
+        <directory>src/main/resources/ui/hive-web/bower_components/voyager</directory>
+        <filtering>false</filtering>
+        <targetPath>voyager</targetPath>
+      </resource>
+      <resource>
+        <targetPath>WEB-INF/lib</targetPath>
+        <filtering>false</filtering>
+        <directory>target/lib</directory>
+      </resource>
+    </resources>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/BaseService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/BaseService.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/BaseService.java
new file mode 100644
index 0000000..773aa55
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/BaseService.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.utils.SharedObjectsFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+
+
+/**
+ * Parent service
+ */
+public class BaseService {
+  @Inject
+  protected ViewContext context;
+
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(BaseService.class);
+
+  private SharedObjectsFactory sharedObjectsFactory;
+  public SharedObjectsFactory getSharedObjectsFactory() {
+    if (sharedObjectsFactory == null) {
+      sharedObjectsFactory = new SharedObjectsFactory(context);
+    }
+    return sharedObjectsFactory;
+  }
+
+  public void setSharedObjectsFactory(SharedObjectsFactory sharedObjectsFactory) {
+    this.sharedObjectsFactory = sharedObjectsFactory;
+  }
+
+  public BaseService() {
+//    Thread.currentThread().setContextClassLoader(null);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionDelegate.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionDelegate.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionDelegate.java
new file mode 100644
index 0000000..918dc68
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionDelegate.java
@@ -0,0 +1,40 @@
+/*
+ * 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.ambari.view.hive2;
+
+import com.google.common.base.Optional;
+import org.apache.ambari.view.hive2.actor.message.DDLJob;
+import org.apache.ambari.view.hive2.actor.message.GetColumnMetadataJob;
+import org.apache.ambari.view.hive2.actor.message.HiveJob;
+import org.apache.ambari.view.hive2.internal.HiveResult;
+import org.apache.hive.jdbc.HiveConnection;
+import org.apache.hive.jdbc.HiveStatement;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public interface ConnectionDelegate {
+  Optional<ResultSet> execute(HiveConnection connection, DDLJob job) throws SQLException;
+  Optional<ResultSet> executeSync(HiveConnection connection, DDLJob job) throws SQLException;
+  Optional<ResultSet> getColumnMetadata(HiveConnection connection, GetColumnMetadataJob job) throws SQLException;
+  Optional<ResultSet> getCurrentResultSet();
+  Optional<HiveStatement> getCurrentStatement();
+  void closeResultSet();
+  void closeStatement();
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionFactory.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionFactory.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionFactory.java
new file mode 100644
index 0000000..2f7ffe0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionFactory.java
@@ -0,0 +1,131 @@
+/*
+ * 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.ambari.view.hive2;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.FluentIterable;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.client.ConnectionConfig;
+
+import java.util.List;
+
+public class ConnectionFactory {
+
+  private static final String ZK_HIVE_DYN_SERVICE_DISCOVERY_KEY = "hive.server2.support.dynamic.service.discovery";
+  private static final String ZK_HIVE_NAMESPACE_KEY = "hive.server2.zookeeper.namespace";
+  private static final String ZK_HIVE_QUORUM = "hive.zookeeper.quorum";
+
+  private static final  String AMBARI_HIVE_SERVICE_NAME = "HIVE";
+  private static final String AMBARI_HIVESERVER_COMPONENT_NAME = "HIVE_SERVER";
+
+  private static final String HIVE_SITE = "hive-site";
+  private static final String HIVE_INTERACTIVE_SITE = "hive-interactive-site";
+
+  private static final String HIVE_JDBC_URL_KEY = "hive.jdbc.url";
+  private static final String HIVE_SESSION_PARAMS = "hive.session.params";
+
+  private static final String BINARY_PORT_KEY = "hive.server2.thrift.port";
+  private static final String HTTP_PORT_KEY = "hive.server2.thrift.http.port";
+  private static final String HIVE_TRANSPORT_MODE_KEY = "hive.server2.transport.mode";
+  private static final String HTTP_PATH_KEY = "hive.server2.thrift.http.path";
+
+
+  public static ConnectionConfig create(ViewContext context) {
+    String jdbcUrl;
+    if (context.getCluster() == null) {
+      jdbcUrl = getConnectFromCustom(context);
+    } else {
+      if (zookeeperConfigured(context)) {
+        jdbcUrl = getFromClusterZookeeperConfig(context);
+      } else {
+        jdbcUrl = getFromHiveConfiguration(context);
+      }
+    }
+
+    String userName = context.getUsername();
+    return new ConnectionConfig(userName, "", jdbcUrl);
+  }
+
+  private static String getFromHiveConfiguration(ViewContext context) {
+    String transportMode = context.getCluster().getConfigurationValue(HIVE_SITE, HIVE_TRANSPORT_MODE_KEY);
+    String binaryPort = context.getCluster().getConfigurationValue(HIVE_SITE, BINARY_PORT_KEY);
+    String httpPort = context.getCluster().getConfigurationValue(HIVE_SITE, HTTP_PORT_KEY);
+    String pathKey = context.getCluster().getConfigurationValue(HIVE_SITE, HTTP_PATH_KEY);
+    List<String> hiveHosts = context.getCluster().getHostsForServiceComponent(AMBARI_HIVE_SERVICE_NAME, AMBARI_HIVESERVER_COMPONENT_NAME);
+    String sessionParams = context.getProperties().get(HIVE_SESSION_PARAMS);
+
+    boolean isBinary = transportMode.equalsIgnoreCase("binary");
+    final String port = isBinary ? binaryPort : httpPort;
+
+    List<String> hostPorts = FluentIterable.from(hiveHosts).transform(new Function<String, String>() {
+      @Override
+      public String apply(String input) {
+        return input + ":" + port;
+      }
+    }).toList();
+
+    String concatHostPorts = Joiner.on(",").join(hostPorts);
+
+    StringBuilder builder = new StringBuilder();
+    builder.append("jdbc:hive2://")
+      .append(concatHostPorts)
+      .append(";")
+      .append(sessionParams);
+
+    if (!isBinary) {
+      builder.append(";").append("transportMode=http;httpPath=").append(pathKey);
+    }
+
+    return builder.toString();
+  }
+
+  private static String getFromClusterZookeeperConfig(ViewContext context) {
+    String quorum = context.getCluster().getConfigurationValue(HIVE_SITE, ZK_HIVE_QUORUM);
+    if (quorum == null) {
+      quorum = context.getCluster().getConfigurationValue(HIVE_INTERACTIVE_SITE, ZK_HIVE_QUORUM);
+    }
+
+    String namespace = context.getCluster().getConfigurationValue(HIVE_SITE, ZK_HIVE_NAMESPACE_KEY);
+    if (namespace == null) {
+      namespace = context.getCluster().getConfigurationValue(HIVE_INTERACTIVE_SITE, ZK_HIVE_NAMESPACE_KEY);
+    }
+
+    String sessionParams = context.getProperties().get(HIVE_SESSION_PARAMS);
+
+    String formatted = String.format("jdbc:hive2://%s/;serviceDiscoveryMode=zooKeeper;zooKeeperNamespace=%s", quorum, namespace);
+    if(!Strings.isNullOrEmpty(sessionParams)){
+      return formatted + ";" + sessionParams;
+    }
+    return formatted;
+  }
+
+  private static boolean zookeeperConfigured(ViewContext context) {
+    boolean fromHiveSite = Boolean.valueOf(context.getCluster().getConfigurationValue(HIVE_SITE, ZK_HIVE_DYN_SERVICE_DISCOVERY_KEY));
+    boolean fromHiveInteractiveSite = Boolean.valueOf(context.getCluster().getConfigurationValue(HIVE_INTERACTIVE_SITE, ZK_HIVE_DYN_SERVICE_DISCOVERY_KEY));
+    return fromHiveInteractiveSite || fromHiveSite;
+  }
+
+  private static String getConnectFromCustom(ViewContext context) {
+    String jdbcUrl = context.getProperties().get(HIVE_JDBC_URL_KEY);
+    String hiveSessionParams = context.getProperties().get(HIVE_SESSION_PARAMS);
+    return jdbcUrl + ";" + hiveSessionParams;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionSystem.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionSystem.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionSystem.java
new file mode 100644
index 0000000..f026ea6
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionSystem.java
@@ -0,0 +1,100 @@
+/*
+ * 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.ambari.view.hive2;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Props;
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.actor.DeathWatch;
+import org.apache.ambari.view.hive2.actor.OperationController;
+import org.apache.ambari.view.hive2.internal.ConnectionSupplier;
+import org.apache.ambari.view.hive2.internal.DataStorageSupplier;
+import org.apache.ambari.view.hive2.internal.HdfsApiSupplier;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+public class ConnectionSystem {
+
+  private static final String ACTOR_CONF_FILE = "application.conf";
+  private static final String ACTOR_SYSTEM_NAME = "HiveViewActorSystem";
+  private ActorSystem actorSystem = null;
+  private static volatile ConnectionSystem instance = null;
+  private static final Object lock = new Object();
+  private static Map<String, ActorRef> operationControllerMap = new HashMap<>();
+
+  private ConnectionSystem() {
+    this.actorSystem = ActorSystem.create(ACTOR_SYSTEM_NAME);;
+  }
+
+  public static ConnectionSystem getInstance() {
+    if(instance == null) {
+      synchronized (lock) {
+        if(instance == null) {
+          instance = new ConnectionSystem();
+        }
+      }
+    }
+    return instance;
+  }
+
+  private ActorRef createOperationController() {
+    ActorRef deathWatch = actorSystem.actorOf(Props.create(DeathWatch.class));
+    return actorSystem.actorOf(
+      Props.create(OperationController.class, actorSystem,deathWatch,
+        new ConnectionSupplier(), new DataStorageSupplier(), new HdfsApiSupplier()));
+  }
+
+  public ActorSystem getActorSystem() {
+    return actorSystem;
+  }
+
+  /**
+   * Returns one operationController per View Instance
+   * @param context
+   * @return operationController Instance
+   */
+  public ActorRef getOperationController(ViewContext context) {
+    String instanceName = context.getInstanceName();
+    ActorRef ref = operationControllerMap.get(instanceName);
+    if(ref == null) {
+      synchronized (lock) {
+        ref = operationControllerMap.get(instanceName);
+        if(ref == null) {
+          ref = createOperationController();
+          operationControllerMap.put(instanceName, ref);
+        }
+      }
+    }
+    return ref;
+  }
+
+  public void shutdown() {
+    if(!actorSystem.isTerminated()) {
+      actorSystem.shutdown();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/HelpService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/HelpService.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/HelpService.java
new file mode 100644
index 0000000..b0316ab
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/HelpService.java
@@ -0,0 +1,118 @@
+/**
+ * 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.ambari.view.hive2;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive2.resources.files.FileService;
+import org.apache.ambari.view.hive2.resources.jobs.atsJobs.ATSParserFactory;
+import org.apache.ambari.view.hive2.resources.jobs.atsJobs.ATSRequestsDelegateImpl;
+import org.json.simple.JSONObject;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Help service
+ */
+public class HelpService extends BaseService {
+  @Inject
+  ViewContext context;
+
+  @Inject
+  protected ViewResourceHandler handler;
+
+  /**
+   * Constructor
+   */
+  public HelpService() {
+    super();
+  }
+
+  /**
+   * Version
+   * @return version
+   */
+  @GET
+  @Path("/version")
+  @Produces(MediaType.TEXT_PLAIN)
+  public Response version(){
+    return Response.ok("0.0.1-SNAPSHOT").build();
+  }
+
+  // ================================================================================
+  // Smoke tests
+  // ================================================================================
+
+  /**
+   * HDFS Status
+   * @return status
+   */
+  @GET
+  @Path("/hdfsStatus")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response hdfsStatus(){
+    FileService.hdfsSmokeTest(context);
+    return getOKResponse();
+  }
+
+  /**
+   * ATS Status
+   * @return status
+   */
+  @GET
+  @Path("/atsStatus")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response atsStatus() {
+    try {
+      ATSRequestsDelegateImpl atsimpl = new ATSRequestsDelegateImpl(context, ATSParserFactory.getATSUrl(context));
+      atsimpl.checkATSStatus();
+      return getOKResponse();
+    }catch (Exception e){
+      throw new WebApplicationException(e);
+    }
+  }
+
+  private Response getOKResponse() {
+    JSONObject response = new JSONObject();
+    response.put("message", "OK");
+    response.put("trace", null);
+    response.put("status", "200");
+    return Response.ok().entity(response).type(MediaType.APPLICATION_JSON).build();
+  }
+
+  /**
+   * Version
+   * @return version
+   */
+  @GET
+  @Path("/test")
+  @Produces(MediaType.TEXT_PLAIN)
+  public Response testStorage(){
+    TestBean test = new TestBean();
+    test.someData = "hello world";
+    getSharedObjectsFactory().getStorage().store(TestBean.class, test);
+    return Response.ok("OK").build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/HiveJdbcConnectionDelegate.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/HiveJdbcConnectionDelegate.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/HiveJdbcConnectionDelegate.java
new file mode 100644
index 0000000..e8d3333
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/HiveJdbcConnectionDelegate.java
@@ -0,0 +1,144 @@
+/*
+ * 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.ambari.view.hive2;
+
+import com.google.common.base.Optional;
+import org.apache.ambari.view.hive2.actor.message.DDLJob;
+import org.apache.ambari.view.hive2.actor.message.GetColumnMetadataJob;
+import org.apache.ambari.view.hive2.actor.message.HiveJob;
+import org.apache.ambari.view.hive2.actor.message.job.Result;
+import org.apache.ambari.view.hive2.internal.HiveResult;
+import org.apache.hive.jdbc.HiveConnection;
+import org.apache.hive.jdbc.HiveStatement;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+public class HiveJdbcConnectionDelegate implements ConnectionDelegate {
+
+  private ResultSet currentResultSet;
+  private HiveStatement currentStatement;
+  private String atsGuid;
+
+  @Override
+  public Optional<ResultSet> execute(HiveConnection connection, DDLJob job) throws SQLException {
+
+    try {
+      Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
+      currentStatement = (HiveStatement) statement;
+
+      for (String syncStatement : job.getSyncStatements()) {
+        // we don't care about the result
+        // fail all if one fails
+        statement.execute(syncStatement);
+      }
+
+      HiveStatement hiveStatement = (HiveStatement) statement;
+      boolean result = hiveStatement.executeAsync(job.getAsyncStatement());
+      atsGuid = hiveStatement.getYarnATSGuid();
+      if (result) {
+        // query has a result set
+        ResultSet resultSet = hiveStatement.getResultSet();
+        currentResultSet = resultSet;
+        Optional<ResultSet> resultSetOptional = Optional.of(resultSet);
+        return resultSetOptional;
+
+      }
+      return Optional.absent();
+
+    } catch (SQLException e) {
+      // Close the statement on any error
+      currentStatement.close();
+      throw e;
+    }
+  }
+
+  @Override
+  public Optional<ResultSet> executeSync(HiveConnection connection, DDLJob job) throws SQLException {
+    try {
+      Statement statement = connection.createStatement();
+      currentStatement = (HiveStatement) statement;
+
+      boolean hasResultSet = false;
+      for (String syncStatement : job.getStatements()) {
+        // we don't care about the result
+        // fail all if one fails
+        hasResultSet = statement.execute(syncStatement);
+      }
+
+      if (hasResultSet) {
+        ResultSet resultSet = statement.getResultSet();
+        //HiveResult result = new HiveResult(resultSet);
+        return Optional.of(resultSet);
+      } else {
+        return Optional.absent();
+      }
+    } catch (SQLException e) {
+      // Close the statement on any error
+      currentStatement.close();
+      throw e;
+    }
+  }
+
+
+  @Override
+  public Optional<ResultSet> getColumnMetadata(HiveConnection connection, GetColumnMetadataJob job) throws SQLException {
+    DatabaseMetaData metaData = connection.getMetaData();
+    ResultSet resultSet = metaData.getColumns("", job.getSchemaPattern(), job.getTablePattern(), job.getColumnPattern());
+    currentResultSet = resultSet;
+    return Optional.of(resultSet);
+  }
+
+  @Override
+  public Optional<ResultSet> getCurrentResultSet() {
+    return Optional.fromNullable(currentResultSet);
+  }
+
+  @Override
+  public Optional<HiveStatement> getCurrentStatement() {
+    return Optional.fromNullable(currentStatement);
+  }
+
+  @Override
+  public void closeResultSet() {
+
+    try {
+      if (currentResultSet != null) {
+        currentResultSet.close();
+      }
+    } catch (SQLException e) {
+      // Cannot do anything here
+    }
+  }
+
+  @Override
+  public void closeStatement()  {
+    try {
+      if (currentStatement != null) {
+        currentStatement.close();
+      }
+    } catch (SQLException e) {
+      // cannot do anything here
+    }
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/HiveViewImpl.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/HiveViewImpl.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/HiveViewImpl.java
new file mode 100644
index 0000000..695c0ab
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/HiveViewImpl.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2;
+
+import org.apache.ambari.view.View;
+import org.apache.ambari.view.ViewDefinition;
+import org.apache.ambari.view.ViewInstanceDefinition;
+import org.apache.ambari.view.hive2.utils.SharedObjectsFactory;
+import org.apache.ambari.view.utils.UserLocal;
+
+
+public class HiveViewImpl implements View {
+  @Override
+  public void onDeploy(ViewDefinition definition) {
+
+  }
+
+  @Override
+  public void onCreate(ViewInstanceDefinition definition) {
+
+  }
+
+  @Override
+  public void onDestroy(ViewInstanceDefinition definition) {
+    SharedObjectsFactory.dropInstanceCache(definition.getInstanceName());
+  }
+
+  @Override
+  public void onUpdate(ViewInstanceDefinition definition) {
+    //drop all cached connection for instance
+    UserLocal.dropInstanceCache(definition.getInstanceName());
+    SharedObjectsFactory.dropInstanceCache(definition.getInstanceName());
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/PropertyValidator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/PropertyValidator.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/PropertyValidator.java
new file mode 100644
index 0000000..e406366
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/PropertyValidator.java
@@ -0,0 +1,98 @@
+/**
+ * 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.ambari.view.hive2;
+
+import org.apache.ambari.view.ViewInstanceDefinition;
+import org.apache.ambari.view.utils.ambari.ValidatorUtils;
+import org.apache.ambari.view.validation.ValidationResult;
+import org.apache.ambari.view.validation.Validator;
+
+public class PropertyValidator implements Validator {
+
+  public static final String WEBHDFS_URL = "webhdfs.url";
+  public static final String HIVE_PORT = "hive.port";
+  public static final String YARN_ATS_URL = "yarn.ats.url";
+  public static final String HIVE_SESSION_PARAMS = "hive.session.params";
+
+  @Override
+  public ValidationResult validateInstance(ViewInstanceDefinition viewInstanceDefinition, ValidationContext validationContext) {
+    return null;
+  }
+
+  @Override
+  public ValidationResult validateProperty(String property, ViewInstanceDefinition viewInstanceDefinition, ValidationContext validationContext) {
+    // Validate non cluster associated properties
+    if (property.equals(HIVE_SESSION_PARAMS)) {
+      String auth = viewInstanceDefinition.getPropertyMap().get(HIVE_SESSION_PARAMS);
+
+      if (auth != null && !auth.isEmpty()) {
+        for(String param : auth.split(";")) {
+          String[] keyvalue = param.split("=");
+          if (keyvalue.length != 2) {
+            return new InvalidPropertyValidationResult(false, "Can not parse session param " + param + " in " + auth);
+          }
+        }
+      }
+    }
+
+    // if associated with cluster, no need to validate associated properties
+    Long cluster = viewInstanceDefinition.getClusterHandle();
+    if (cluster != null) {
+      return ValidationResult.SUCCESS;
+    }
+
+    // Cluster associated properties
+    if (property.equals(WEBHDFS_URL)) {
+      String webhdfsUrl = viewInstanceDefinition.getPropertyMap().get(WEBHDFS_URL);
+      if (!ValidatorUtils.validateHdfsURL(webhdfsUrl)) {
+        return new InvalidPropertyValidationResult(false, "Must be valid URL");
+      }
+    }
+
+    if (property.equals(YARN_ATS_URL)) {
+      String atsUrl = viewInstanceDefinition.getPropertyMap().get(YARN_ATS_URL);
+      if (!ValidatorUtils.validateHttpURL(atsUrl)) {
+        return new InvalidPropertyValidationResult(false, "Must be valid URL");
+      }
+    }
+
+    return ValidationResult.SUCCESS;
+  }
+
+  public static class InvalidPropertyValidationResult implements ValidationResult {
+    private boolean valid;
+    private String detail;
+
+    public InvalidPropertyValidationResult(boolean valid, String detail) {
+      this.valid = valid;
+      this.detail = detail;
+    }
+
+    @Override
+    public boolean isValid() {
+      return valid;
+    }
+
+    @Override
+    public String getDetail() {
+      return detail;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/TestBean.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/TestBean.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/TestBean.java
new file mode 100644
index 0000000..4b49f64
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/TestBean.java
@@ -0,0 +1,36 @@
+/**
+ * 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.ambari.view.hive2;
+
+import org.apache.ambari.view.hive2.persistence.utils.Indexed;
+
+public class TestBean implements Indexed {
+  public String someData;
+  public String id;
+
+  @Override
+  public String getId() {
+    return id;
+  }
+
+  @Override
+  public void setId(String id) {
+    this.id = id;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/AsyncJdbcConnector.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/AsyncJdbcConnector.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/AsyncJdbcConnector.java
new file mode 100644
index 0000000..9d3517f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/AsyncJdbcConnector.java
@@ -0,0 +1,191 @@
+/*
+ * 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.ambari.view.hive2.actor;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.PoisonPill;
+import akka.actor.Props;
+import com.google.common.base.Optional;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.ConnectionDelegate;
+import org.apache.ambari.view.hive2.actor.message.AsyncJob;
+import org.apache.ambari.view.hive2.actor.message.HiveMessage;
+import org.apache.ambari.view.hive2.actor.message.RegisterActor;
+import org.apache.ambari.view.hive2.actor.message.ResultReady;
+import org.apache.ambari.view.hive2.actor.message.StartLogAggregation;
+import org.apache.ambari.view.hive2.actor.message.job.AsyncExecutionFailed;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.InactivityCheck;
+import org.apache.ambari.view.hive2.internal.Either;
+import org.apache.ambari.view.hive2.persistence.Storage;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.Job;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobImpl;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.hive.jdbc.HiveConnection;
+import org.apache.hive.jdbc.HiveStatement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.concurrent.duration.Duration;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.concurrent.TimeUnit;
+
+public class AsyncJdbcConnector extends JdbcConnector {
+
+  private final Logger LOG = LoggerFactory.getLogger(getClass());
+
+  private ActorRef logAggregator = null;
+  private ActorRef asyncQueryExecutor = null;
+  private ActorRef resultSetActor = null;
+
+
+  public AsyncJdbcConnector(ViewContext viewContext, HdfsApi hdfsApi, ActorSystem system, ActorRef parent,ActorRef deathWatch, ConnectionDelegate connectionDelegate, Storage storage) {
+    super(viewContext, hdfsApi, system, parent,deathWatch, connectionDelegate, storage);
+  }
+
+  @Override
+  protected void handleJobMessage(HiveMessage message) {
+    Object job = message.getMessage();
+    if (job instanceof AsyncJob) {
+      LOG.debug("Executing async job " + message.toString());
+      execute((AsyncJob) job);
+    }
+  }
+
+  @Override
+  protected boolean isAsync() {
+    return true;
+  }
+
+  @Override
+  protected void cleanUpChildren() {
+    if(logAggregator != null && !logAggregator.isTerminated()) {
+      LOG.debug("Sending poison pill to log aggregator");
+      logAggregator.tell(PoisonPill.getInstance(), self());
+    }
+
+    if(asyncQueryExecutor != null && !asyncQueryExecutor.isTerminated()) {
+      LOG.debug("Sending poison pill to Async Query Executor");
+      asyncQueryExecutor.tell(PoisonPill.getInstance(), self());
+    }
+
+    if(resultSetActor != null && !resultSetActor.isTerminated()) {
+      LOG.debug("Sending poison pill to Resultset Actor");
+      resultSetActor.tell(PoisonPill.getInstance(), self());
+    }
+  }
+
+  @Override
+  protected void notifyFailure() {
+    AsyncExecutionFailed failure = new AsyncExecutionFailed(jobId,username,"Cannot connect to hive");
+    parent.tell(failure, self());
+  }
+
+  private void execute(AsyncJob message) {
+    this.executing = true;
+    this.jobId = message.getJobId();
+    updateJobStatus(jobId,Job.JOB_STATE_INITIALIZED);
+    if (connectable == null) {
+      notifyAndCleanUp();
+      return;
+    }
+
+    Optional<HiveConnection> connectionOptional = connectable.getConnection();
+    if (!connectionOptional.isPresent()) {
+      notifyAndCleanUp();
+      return;
+    }
+
+    try {
+      Optional<ResultSet> resultSetOptional = connectionDelegate.execute(connectionOptional.get(), message);
+      Optional<HiveStatement> currentStatement = connectionDelegate.getCurrentStatement();
+      // There should be a result set, which either has a result set, or an empty value
+      // for operations which do not return anything
+
+      logAggregator = getContext().actorOf(
+        Props.create(LogAggregator.class, system, hdfsApi, currentStatement.get(), message.getLogFile())
+        .withDispatcher("akka.actor.misc-dispatcher"),   message.getJobId() + ":" +"-logAggregator"
+      );
+      deathWatch.tell(new RegisterActor(logAggregator),self());
+
+      updateGuidInJob(jobId, currentStatement.get());
+      updateJobStatus(jobId,Job.JOB_STATE_RUNNING);
+
+      if (resultSetOptional.isPresent()) {
+        // Start a result set aggregator on the same context, a notice to the parent will kill all these as well
+        // tell the result holder to assign the result set for further operations
+        resultSetActor = getContext().actorOf(Props.create(ResultSetIterator.class, self(),
+          resultSetOptional.get(),storage).withDispatcher("akka.actor.result-dispatcher"),
+          "ResultSetActor:ResultSetIterator:JobId:"+ jobId );
+        deathWatch.tell(new RegisterActor(resultSetActor),self());
+        parent.tell(new ResultReady(jobId,username, Either.<ActorRef, ActorRef>left(resultSetActor)), self());
+
+        // Start a actor to query ATS
+      } else {
+        // Case when this is an Update/query with no results
+        // Wait for operation to complete and add results;
+
+        ActorRef asyncQueryExecutor = getContext().actorOf(
+                Props.create(AsyncQueryExecutor.class, parent, currentStatement.get(),storage,jobId,username)
+                  .withDispatcher("akka.actor.result-dispatcher"),
+                 message.getJobId() + "-asyncQueryExecutor");
+        deathWatch.tell(new RegisterActor(asyncQueryExecutor),self());
+        parent.tell(new ResultReady(jobId,username, Either.<ActorRef, ActorRef>right(asyncQueryExecutor)), self());
+
+      }
+      // Start a actor to query log
+      logAggregator.tell(new StartLogAggregation(), self());
+
+
+    } catch (SQLException e) {
+      // update the error on the log
+      AsyncExecutionFailed failure = new AsyncExecutionFailed(message.getJobId(),username,
+              e.getMessage(), e);
+      updateJobStatus(jobId,Job.JOB_STATE_ERROR);
+      parent.tell(failure, self());
+      // Update the operation controller to write an error on tshe right side
+      LOG.error("Caught SQL excpetion for job-"+message,e);
+
+    }
+
+    // Start Inactivity timer to close the statement
+    this.inactivityScheduler = system.scheduler().schedule(
+      Duration.Zero(), Duration.create(15 * 1000, TimeUnit.MILLISECONDS),
+      this.self(), new InactivityCheck(), system.dispatcher(), null);
+  }
+
+  private void notifyAndCleanUp() {
+    updateJobStatus(jobId, Job.JOB_STATE_ERROR);
+    notifyFailure();
+    cleanUp();
+  }
+
+  private void updateJobStatus(String jobId, String jobState) {
+    JobImpl job = null;
+    try {
+      job = storage.load(JobImpl.class, jobId);
+    } catch (ItemNotFound itemNotFound) {
+      itemNotFound.printStackTrace();
+    }
+    job.setStatus(jobState);
+    storage.store(JobImpl.class, job);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/AsyncQueryExecutor.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/AsyncQueryExecutor.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/AsyncQueryExecutor.java
new file mode 100644
index 0000000..2a1dbb3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/AsyncQueryExecutor.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.actor;
+
+import akka.actor.ActorRef;
+import org.apache.ambari.view.hive2.actor.message.ExecuteQuery;
+import org.apache.ambari.view.hive2.actor.message.HiveMessage;
+import org.apache.ambari.view.hive2.actor.message.job.AsyncExecutionFailed;
+import org.apache.ambari.view.hive2.actor.message.job.ExecutionFailed;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.CleanUp;
+import org.apache.ambari.view.hive2.internal.AsyncExecutionSuccess;
+import org.apache.ambari.view.hive2.persistence.Storage;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.Job;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.SQLException;
+import java.sql.Statement;
+
+public class AsyncQueryExecutor extends HiveActor {
+  private final Logger LOG = LoggerFactory.getLogger(getClass());
+
+  private Statement statement;
+  private final Storage storage;
+  private final String jobId;
+  private final ActorRef parent;
+  private final String userName;
+
+  public AsyncQueryExecutor(ActorRef parent, Statement statement, Storage storage, String jobId,String userName) {
+    this.statement = statement;
+    this.storage = storage;
+    this.jobId = jobId;
+    this.parent = parent;
+    this.userName = userName;
+  }
+
+  @Override
+  public void handleMessage(HiveMessage hiveMessage) {
+    Object message = hiveMessage.getMessage();
+
+    if (message instanceof ExecuteQuery) {
+      executeQuery();
+    }
+
+  }
+
+  private void executeQuery() {
+    JobImpl job = null;
+    try {
+      job = storage.load(JobImpl.class, jobId);
+      statement.getUpdateCount();
+      LOG.info("Job execution successful. Setting status in db.");
+      job.setStatus(Job.JOB_STATE_FINISHED);
+      storage.store(JobImpl.class, job);
+      sender().tell(new AsyncExecutionSuccess(), self());
+
+    } catch (SQLException e) {
+      job.setStatus(Job.JOB_STATE_ERROR);
+      sender().tell(new AsyncExecutionFailed(jobId,userName, e.getMessage(), e), self());
+      storage.store(JobImpl.class, job);
+    } catch (ItemNotFound itemNotFound) {
+      sender().tell(new AsyncExecutionFailed(jobId,userName, "Cannot load job", itemNotFound), self());
+    } finally {
+      // We can clean up this connection here
+      parent.tell(new CleanUp(), self());
+    }
+
+  }
+
+
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/DeathWatch.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/DeathWatch.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/DeathWatch.java
new file mode 100644
index 0000000..c146dd0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/DeathWatch.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.actor;
+
+import akka.actor.ActorRef;
+import akka.actor.Terminated;
+import org.apache.ambari.view.hive2.actor.message.HiveMessage;
+import org.apache.ambari.view.hive2.actor.message.RegisterActor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+
+public class DeathWatch extends HiveActor {
+
+    private final static Logger LOG =
+            LoggerFactory.getLogger(DeathWatch.class);
+
+    @Override
+    void handleMessage(HiveMessage hiveMessage) {
+        Object message = hiveMessage.getMessage();
+        if(message instanceof RegisterActor){
+            RegisterActor registerActor = (RegisterActor) message;
+            ActorRef actorRef = registerActor.getActorRef();
+            this.getContext().watch(actorRef);
+            LOG.info("Registered new actor "+ actorRef);
+            LOG.info("Registration for {} at {}", actorRef,new Date());
+        }
+        if(message instanceof Terminated){
+            Terminated terminated = (Terminated) message;
+            ActorRef actor = terminated.actor();
+            LOG.info("Received terminate for actor "+ actor);
+            LOG.info("Termination for {} at {}", actor,new Date());
+
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/GetResultHolder.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/GetResultHolder.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/GetResultHolder.java
new file mode 100644
index 0000000..c2ee5c7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/GetResultHolder.java
@@ -0,0 +1,47 @@
+/*
+ * 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.ambari.view.hive2.actor;
+
+public class GetResultHolder {
+
+    private String jobId;
+    private String userName;
+
+    public GetResultHolder(String jobId, String userName) {
+        this.jobId = jobId;
+        this.userName = userName;
+    }
+
+
+    public String getJobId() {
+        return jobId;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    @Override
+    public String toString() {
+        return "GetResultHolder{" +
+                "jobId='" + jobId + '\'' +
+                ", userName='" + userName + '\'' +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/HiveActor.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/HiveActor.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/HiveActor.java
new file mode 100644
index 0000000..63e5dd1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/HiveActor.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.actor;
+
+import akka.actor.UntypedActor;
+import org.apache.ambari.view.hive2.actor.message.HiveMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class HiveActor extends UntypedActor {
+
+    private final Logger LOG = LoggerFactory.getLogger(getClass());
+
+    @Override
+    final public void onReceive(Object message) throws Exception {
+        HiveMessage hiveMessage = new HiveMessage(message);
+        if(LOG.isDebugEnabled()){
+            LOG.debug("Received message: " + message.getClass().getName() + ", generated id: " + hiveMessage.getId() +
+                    " sent by: " + sender() + ", recieved by" + self());
+        }
+
+        handleMessage(hiveMessage);
+
+        if(LOG.isDebugEnabled()){
+            LOG.debug("Message submitted: " + hiveMessage.getId());
+
+        }
+    }
+
+    abstract void handleMessage(HiveMessage hiveMessage);
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/JdbcConnector.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/JdbcConnector.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/JdbcConnector.java
new file mode 100644
index 0000000..7769dde
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/JdbcConnector.java
@@ -0,0 +1,305 @@
+/*
+ * 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.ambari.view.hive2.actor;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Cancellable;
+import akka.actor.PoisonPill;
+import com.google.common.base.Optional;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.ConnectionDelegate;
+import org.apache.ambari.view.hive2.actor.message.Connect;
+import org.apache.ambari.view.hive2.actor.message.HiveMessage;
+import org.apache.ambari.view.hive2.actor.message.JobExecutionCompleted;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.CleanUp;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.DestroyConnector;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.FreeConnector;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.InactivityCheck;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.KeepAlive;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.TerminateInactivityCheck;
+import org.apache.ambari.view.hive2.internal.Connectable;
+import org.apache.ambari.view.hive2.internal.ConnectionException;
+import org.apache.ambari.view.hive2.persistence.Storage;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobImpl;
+import org.apache.ambari.view.hive2.utils.HiveActorConfiguration;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.hive.jdbc.HiveStatement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.concurrent.duration.Duration;
+
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * Wraps one Jdbc connection per user, per instance. This is used to delegate execute the statements and
+ * creates child actors to delegate the resultset extraction, YARN/ATS querying for ExecuteJob info and Log Aggregation
+ */
+public abstract class JdbcConnector extends HiveActor {
+
+  private final Logger LOG = LoggerFactory.getLogger(getClass());
+
+  /**
+   * Interval for maximum inactivity allowed
+   */
+  private final static long MAX_INACTIVITY_INTERVAL = 5 * 60 * 1000;
+
+  /**
+   * Interval for maximum inactivity allowed before termination
+   */
+  private static final long MAX_TERMINATION_INACTIVITY_INTERVAL = 10 * 60 * 1000;
+
+  protected final ViewContext viewContext;
+  protected final ActorSystem system;
+  protected final Storage storage;
+
+  /**
+   * Keeps track of the timestamp when the last activity has happened. This is
+   * used to calculate the inactivity period and take lifecycle decisions based
+   * on it.
+   */
+  private long lastActivityTimestamp;
+
+  /**
+   * Akka scheduler to tick at an interval to deal with inactivity of this actor
+   */
+  protected Cancellable inactivityScheduler;
+
+  /**
+   * Akka scheduler to tick at an interval to deal with the inactivity after which
+   * the actor should be killed and connectable should be released
+   */
+  protected Cancellable terminateActorScheduler;
+
+  protected Connectable connectable = null;
+  protected final ActorRef deathWatch;
+  protected final ConnectionDelegate connectionDelegate;
+  protected final ActorRef parent;
+  protected final HdfsApi hdfsApi;
+
+  /**
+   * true if the actor is currently executing any job.
+   */
+  protected boolean executing = false;
+
+  /**
+   * true if the currently executing job is async job.
+   */
+  private boolean async = true;
+
+  /**
+   * Returns the timeout configurations.
+   */
+  private final HiveActorConfiguration actorConfiguration;
+  protected String username;
+  protected String jobId;
+
+  public JdbcConnector(ViewContext viewContext, HdfsApi hdfsApi, ActorSystem system, ActorRef parent, ActorRef deathWatch,
+                       ConnectionDelegate connectionDelegate, Storage storage) {
+    this.viewContext = viewContext;
+    this.hdfsApi = hdfsApi;
+    this.system = system;
+    this.parent = parent;
+    this.deathWatch = deathWatch;
+    this.connectionDelegate = connectionDelegate;
+    this.storage = storage;
+    this.lastActivityTimestamp = System.currentTimeMillis();
+    actorConfiguration = new HiveActorConfiguration(viewContext);
+  }
+
+  @Override
+  public void handleMessage(HiveMessage hiveMessage) {
+    Object message = hiveMessage.getMessage();
+    if (message instanceof InactivityCheck) {
+      checkInactivity();
+    } else if (message instanceof TerminateInactivityCheck) {
+      checkTerminationInactivity();
+    } else if (message instanceof KeepAlive) {
+      keepAlive();
+    } else if (message instanceof CleanUp) {
+      cleanUp();
+    } else if (message instanceof JobExecutionCompleted) {
+      jobExecutionCompleted();
+    } else {
+      handleNonLifecycleMessage(hiveMessage);
+    }
+  }
+
+  private void handleNonLifecycleMessage(HiveMessage hiveMessage) {
+    Object message = hiveMessage.getMessage();
+    keepAlive();
+    if (message instanceof Connect) {
+      connect((Connect) message);
+    } else {
+      handleJobMessage(hiveMessage);
+    }
+
+  }
+
+  protected abstract void handleJobMessage(HiveMessage message);
+
+  protected abstract boolean isAsync();
+
+  protected abstract void notifyFailure();
+
+  protected abstract void cleanUpChildren();
+
+  private void keepAlive() {
+    lastActivityTimestamp = System.currentTimeMillis();
+  }
+
+  private void jobExecutionCompleted() {
+    // Set is executing as false so that the inactivity checks can finish cleanup
+    // after timeout
+    LOG.info("Job execution completed for user: {}. Results are ready to be fetched", username);
+    this.executing = false;
+  }
+
+  protected Optional<String> getJobId() {
+    return Optional.fromNullable(jobId);
+  }
+
+  protected Optional<String> getUsername() {
+    return Optional.fromNullable(username);
+  }
+
+  private void connect(Connect message) {
+    this.username = message.getUsername();
+    // check the connectable
+    if (connectable == null) {
+      connectable = message.getConnectable();
+    }
+    // make the connectable to Hive
+    try {
+      if (!connectable.isOpen()) {
+        connectable.connect();
+      }
+    } catch (ConnectionException e) {
+      // set up job failure
+      // notify parent about job failure
+      this.notifyFailure();
+      cleanUp();
+      return;
+    }
+
+    this.terminateActorScheduler = system.scheduler().schedule(
+      Duration.Zero(), Duration.create(60 * 1000, TimeUnit.MILLISECONDS),
+      this.getSelf(), new TerminateInactivityCheck(), system.dispatcher(), null);
+
+  }
+
+  protected void updateGuidInJob(String jobId, HiveStatement statement) {
+    String yarnAtsGuid = statement.getYarnATSGuid();
+    try {
+      JobImpl job = storage.load(JobImpl.class, jobId);
+      job.setGuid(yarnAtsGuid);
+      storage.store(JobImpl.class, job);
+    } catch (ItemNotFound itemNotFound) {
+      // Cannot do anything if the job is not present
+    }
+  }
+
+  private void checkInactivity() {
+    LOG.info("Inactivity check, executing status: {}", executing);
+    if (executing) {
+      keepAlive();
+      return;
+    }
+    long current = System.currentTimeMillis();
+    if ((current - lastActivityTimestamp) > actorConfiguration.getInactivityTimeout(MAX_INACTIVITY_INTERVAL)) {
+      // Stop all the sub-actors created
+      cleanUp();
+    }
+  }
+
+  private void checkTerminationInactivity() {
+    if (!isAsync()) {
+      // Should not terminate if job is sync. Will terminate after the job is finished.
+      stopTeminateInactivityScheduler();
+      return;
+    }
+
+    LOG.info("Termination check, executing status: {}", executing);
+    if (executing) {
+      keepAlive();
+      return;
+    }
+
+    long current = System.currentTimeMillis();
+    if ((current - lastActivityTimestamp) > actorConfiguration.getTerminationTimeout(MAX_TERMINATION_INACTIVITY_INTERVAL)) {
+      cleanUpWithTermination();
+    }
+  }
+
+  protected void cleanUp() {
+    if(jobId != null) {
+      LOG.debug("{} :: Cleaning up resources for inactivity for jobId: {}", self().path().name(), jobId);
+    } else {
+      LOG.debug("{} ::Cleaning up resources with inactivity for Sync execution.", self().path().name());
+    }
+    this.executing = false;
+    cleanUpStatementAndResultSet();
+    cleanUpChildren();
+    stopInactivityScheduler();
+    parent.tell(new FreeConnector(username, jobId, isAsync()), self());
+  }
+
+  protected void cleanUpWithTermination() {
+    LOG.debug("{} :: Cleaning up resources with inactivity for Sync execution.", self().path().name());
+    cleanUpStatementAndResultSet();
+
+    cleanUpChildren();
+    stopInactivityScheduler();
+    stopTeminateInactivityScheduler();
+    parent.tell(new DestroyConnector(username, jobId, isAsync()), this.self());
+    self().tell(PoisonPill.getInstance(), ActorRef.noSender());
+  }
+
+
+  private void cleanUpStatementAndResultSet() {
+    connectionDelegate.closeStatement();
+    connectionDelegate.closeResultSet();
+  }
+
+  private void stopTeminateInactivityScheduler() {
+    if (!(terminateActorScheduler == null || terminateActorScheduler.isCancelled())) {
+      terminateActorScheduler.cancel();
+    }
+  }
+
+  private void stopInactivityScheduler() {
+    if (!(inactivityScheduler == null || inactivityScheduler.isCancelled())) {
+      inactivityScheduler.cancel();
+    }
+  }
+
+  @Override
+  public void postStop() throws Exception {
+    stopInactivityScheduler();
+    stopTeminateInactivityScheduler();
+
+    if (connectable.isOpen()) {
+      connectable.disconnect();
+    }
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/LogAggregator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/LogAggregator.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/LogAggregator.java
new file mode 100644
index 0000000..284345d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/LogAggregator.java
@@ -0,0 +1,109 @@
+/*
+ * 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.ambari.view.hive2.actor;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Cancellable;
+import com.google.common.base.Joiner;
+import org.apache.ambari.view.hive2.actor.message.GetMoreLogs;
+import org.apache.ambari.view.hive2.actor.message.HiveMessage;
+import org.apache.ambari.view.hive2.actor.message.LogAggregationFinished;
+import org.apache.ambari.view.hive2.actor.message.StartLogAggregation;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.ambari.view.utils.hdfs.HdfsApiException;
+import org.apache.ambari.view.utils.hdfs.HdfsUtil;
+import org.apache.hive.jdbc.HiveStatement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.concurrent.duration.Duration;
+
+import java.sql.SQLException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Reads the logs for a ExecuteJob from the Statement and writes them into hdfs.
+ */
+public class LogAggregator extends HiveActor {
+
+  private final Logger LOG = LoggerFactory.getLogger(getClass());
+
+  public static final int AGGREGATION_INTERVAL = 5 * 1000;
+  private final HdfsApi hdfsApi;
+  private final HiveStatement statement;
+  private final String logFile;
+  private final ActorSystem system;
+
+  private Cancellable moreLogsScheduler;
+  private ActorRef parent;
+
+  public LogAggregator(ActorSystem system, HdfsApi hdfsApi, HiveStatement statement, String logFile) {
+    this.system = system;
+    this.hdfsApi = hdfsApi;
+    this.statement = statement;
+    this.logFile = logFile;
+  }
+
+  @Override
+  public void handleMessage(HiveMessage hiveMessage) {
+    Object message = hiveMessage.getMessage();
+    if (message instanceof StartLogAggregation) {
+      start();
+    }
+
+    if (message instanceof GetMoreLogs) {
+      try {
+        getMoreLogs();
+      } catch (SQLException e) {
+        LOG.error("SQL Error while getting logs. Tried writing to: {}", logFile);
+      } catch (HdfsApiException e) {
+        LOG.warn("HDFS Error while getting writing logs to {}", logFile);
+
+      }
+    }
+  }
+
+  private void start() {
+    parent = this.getSender();
+    this.moreLogsScheduler = system.scheduler().schedule(
+      Duration.Zero(), Duration.create(AGGREGATION_INTERVAL, TimeUnit.MILLISECONDS),
+      this.getSelf(), new GetMoreLogs(), system.dispatcher(), null);
+  }
+
+  private void getMoreLogs() throws SQLException, HdfsApiException {
+    if (statement.hasMoreLogs()) {
+      List<String> logs = statement.getQueryLog();
+      String allLogs = Joiner.on("\n").skipNulls().join(logs);
+      HdfsUtil.putStringToFile(hdfsApi, logFile, allLogs);
+    } else {
+      moreLogsScheduler.cancel();
+      parent.tell(new LogAggregationFinished(), ActorRef.noSender());
+    }
+  }
+
+  @Override
+  public void postStop() throws Exception {
+    if(moreLogsScheduler != null && !moreLogsScheduler.isCancelled()){
+      moreLogsScheduler.cancel();
+    }
+
+  }
+
+}


[18/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/NoMoreItems.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/NoMoreItems.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/NoMoreItems.java
new file mode 100644
index 0000000..aca5ba9
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/NoMoreItems.java
@@ -0,0 +1,21 @@
+/*
+ * 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.ambari.view.hive2.actor.message.job;
+
+public class NoMoreItems {}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/NoResult.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/NoResult.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/NoResult.java
new file mode 100644
index 0000000..02833e6
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/NoResult.java
@@ -0,0 +1,21 @@
+/*
+ * 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.ambari.view.hive2.actor.message.job;
+
+public class NoResult {}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/Result.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/Result.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/Result.java
new file mode 100644
index 0000000..df1d52e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/Result.java
@@ -0,0 +1,43 @@
+/*
+ * 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.ambari.view.hive2.actor.message.job;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.ambari.view.hive2.client.ColumnDescription;
+import org.apache.ambari.view.hive2.client.Row;
+
+import java.util.List;
+
+public class Result {
+  private final List<ColumnDescription> columns;
+  private final List<Row> rows;
+
+  public Result(List<Row> rows, List<ColumnDescription> columns) {
+    this.rows = ImmutableList.copyOf(rows);
+    this.columns = columns;
+  }
+
+  public List<Row> getRows() {
+    return rows;
+  }
+
+  public List<ColumnDescription> getColumns() {
+    return columns;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/ResultSetHolder.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/ResultSetHolder.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/ResultSetHolder.java
new file mode 100644
index 0000000..a54214f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/job/ResultSetHolder.java
@@ -0,0 +1,33 @@
+/*
+ * 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.ambari.view.hive2.actor.message.job;
+
+import akka.actor.ActorRef;
+
+public class ResultSetHolder {
+  private final ActorRef iterator;
+
+  public ResultSetHolder(ActorRef iterator) {
+    this.iterator = iterator;
+  }
+
+  public ActorRef getIterator() {
+    return iterator;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/CleanUp.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/CleanUp.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/CleanUp.java
new file mode 100644
index 0000000..33dce72
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/CleanUp.java
@@ -0,0 +1,21 @@
+/*
+ * 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.ambari.view.hive2.actor.message.lifecycle;
+
+public class CleanUp {}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/DestroyConnector.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/DestroyConnector.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/DestroyConnector.java
new file mode 100644
index 0000000..29a56a2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/DestroyConnector.java
@@ -0,0 +1,52 @@
+/*
+ * 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.ambari.view.hive2.actor.message.lifecycle;
+
+public class DestroyConnector {
+  private final String username;
+  private final String jobId;
+  private final boolean forAsync;
+
+  public DestroyConnector(String username, String jobId, boolean forAsync) {
+    this.username = username;
+    this.jobId = jobId;
+    this.forAsync = forAsync;
+  }
+
+  public String getUsername() {
+    return username;
+  }
+
+  public String getJobId() {
+    return jobId;
+  }
+
+  public boolean isForAsync() {
+    return forAsync;
+  }
+
+  @Override
+  public String toString() {
+    return "DestroyConnector{" +
+      "username='" + username + '\'' +
+      ", jobId='" + jobId + '\'' +
+      ", forAsync=" + forAsync +
+      '}';
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/FreeConnector.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/FreeConnector.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/FreeConnector.java
new file mode 100644
index 0000000..bfd7b3b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/FreeConnector.java
@@ -0,0 +1,53 @@
+/*
+ * 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.ambari.view.hive2.actor.message.lifecycle;
+
+public class FreeConnector  {
+
+  private final String username;
+  private final String jobId;
+  private final boolean forAsync;
+
+  public FreeConnector(String username, String jobId, boolean forAsync) {
+    this.username = username;
+    this.jobId = jobId;
+    this.forAsync = forAsync;
+  }
+
+  public String getUsername() {
+    return username;
+  }
+
+  public String getJobId() {
+    return jobId;
+  }
+
+  public boolean isForAsync() {
+    return forAsync;
+  }
+
+  @Override
+  public String toString() {
+    return "FreeConnector{" +
+      "username='" + username + '\'' +
+      ", jobId='" + jobId + '\'' +
+      ", forAsync=" + forAsync +
+      '}';
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/InactivityCheck.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/InactivityCheck.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/InactivityCheck.java
new file mode 100644
index 0000000..ead3cb7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/InactivityCheck.java
@@ -0,0 +1,21 @@
+/*
+ * 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.ambari.view.hive2.actor.message.lifecycle;
+
+public class InactivityCheck {}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/KeepAlive.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/KeepAlive.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/KeepAlive.java
new file mode 100644
index 0000000..565a6ae
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/KeepAlive.java
@@ -0,0 +1,21 @@
+/*
+ * 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.ambari.view.hive2.actor.message.lifecycle;
+
+public class KeepAlive {}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/TerminateInactivityCheck.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/TerminateInactivityCheck.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/TerminateInactivityCheck.java
new file mode 100644
index 0000000..0096ced
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/message/lifecycle/TerminateInactivityCheck.java
@@ -0,0 +1,21 @@
+/*
+ * 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.ambari.view.hive2.actor.message.lifecycle;
+
+public class TerminateInactivityCheck {}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/backgroundjobs/BackgroundJobController.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/backgroundjobs/BackgroundJobController.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/backgroundjobs/BackgroundJobController.java
new file mode 100644
index 0000000..bd3bb23
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/backgroundjobs/BackgroundJobController.java
@@ -0,0 +1,84 @@
+/**
+ * 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.ambari.view.hive2.backgroundjobs;
+
+import org.apache.ambari.view.ViewContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class BackgroundJobController {
+  private ViewContext context;
+
+  protected BackgroundJobController(ViewContext context) {
+    this.context = context;
+  }
+
+  private static Map<String, BackgroundJobController> viewSingletonObjects = new HashMap<String, BackgroundJobController>();
+  public static BackgroundJobController getInstance(ViewContext context) {
+    if (!viewSingletonObjects.containsKey(context.getInstanceName()))
+      viewSingletonObjects.put(context.getInstanceName(), new BackgroundJobController(context));
+    return viewSingletonObjects.get(context.getInstanceName());
+  }
+
+  private Map<String, Thread> jobs = new HashMap<String, Thread>();
+  public void startJob(String key, Runnable runnable) {
+    if (jobs.containsKey(key)) {
+      interrupt(key);
+      try {
+        jobs.get(key).join();
+      } catch (InterruptedException ignored) {
+      }
+    }
+    Thread t = new Thread(runnable);
+    jobs.put(key, t);
+    t.start();
+  }
+
+  public Thread.State state(String key) {
+    if (!jobs.containsKey(key)) {
+      return Thread.State.TERMINATED;
+    }
+
+    Thread.State state = jobs.get(key).getState();
+
+    if (state == Thread.State.TERMINATED) {
+      jobs.remove(key);
+    }
+
+    return state;
+  }
+
+  public boolean interrupt(String key) {
+    if (!jobs.containsKey(key)) {
+      return false;
+    }
+
+    jobs.get(key).interrupt();
+    return true;
+  }
+
+  public boolean isInterrupted(String key) {
+    if (state(key) == Thread.State.TERMINATED) {
+      return true;
+    }
+
+    return jobs.get(key).isInterrupted();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunner.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunner.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunner.java
new file mode 100644
index 0000000..829e57c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunner.java
@@ -0,0 +1,36 @@
+/*
+ * 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.ambari.view.hive2.client;
+
+import com.google.common.base.Optional;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.Job;
+import org.apache.ambari.view.hive2.actor.message.AsyncJob;
+import org.apache.ambari.view.hive2.actor.message.job.AsyncExecutionFailed;
+
+public interface AsyncJobRunner {
+
+    void submitJob(ConnectionConfig connectionConfig, AsyncJob asyncJob, Job job);
+
+    Optional<NonPersistentCursor> getCursor(String jobId, String username);
+
+    Optional<NonPersistentCursor> resetAndGetCursor(String jobId, String username);
+
+    Optional<AsyncExecutionFailed> getError(String jobId, String username);
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunnerImpl.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunnerImpl.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunnerImpl.java
new file mode 100644
index 0000000..f9e6d67
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunnerImpl.java
@@ -0,0 +1,115 @@
+/*
+ * 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.ambari.view.hive2.client;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Inbox;
+import com.google.common.base.Optional;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.actor.message.CursorReset;
+import org.apache.ambari.view.hive2.actor.message.FetchError;
+import org.apache.ambari.view.hive2.actor.message.ResetCursor;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.Job;
+import org.apache.ambari.view.hive2.actor.message.AsyncJob;
+import org.apache.ambari.view.hive2.actor.message.Connect;
+import org.apache.ambari.view.hive2.actor.message.ExecuteJob;
+import org.apache.ambari.view.hive2.actor.message.FetchResult;
+import org.apache.ambari.view.hive2.actor.message.job.AsyncExecutionFailed;
+import org.apache.ambari.view.hive2.internal.Either;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.concurrent.duration.Duration;
+
+import java.util.concurrent.TimeUnit;
+
+public class AsyncJobRunnerImpl implements AsyncJobRunner {
+
+  private final Logger LOG = LoggerFactory.getLogger(getClass());
+
+  private final ActorRef controller;
+  private final ActorSystem system;
+  private final ViewContext context;
+
+  public AsyncJobRunnerImpl(ViewContext context, ActorRef controller, ActorSystem system) {
+    this.context = context;
+    this.controller = controller;
+    this.system = system;
+  }
+
+
+
+    @Override
+    public void submitJob(ConnectionConfig config, AsyncJob job, Job jobp) {
+        Connect connect = config.createConnectMessage();
+        ExecuteJob executeJob = new ExecuteJob(connect, job);
+        controller.tell(executeJob,ActorRef.noSender());
+    }
+
+  @Override
+  public Optional<NonPersistentCursor> getCursor(String jobId, String username) {
+    Inbox inbox = Inbox.create(system);
+    inbox.send(controller, new FetchResult(jobId, username));
+    Object receive = inbox.receive(Duration.create(1, TimeUnit.MINUTES));
+    Either<ActorRef, ActorRef> result = (Either<ActorRef, ActorRef>) receive;
+    if (result.isRight()) {
+      return Optional.absent();
+
+    } else if (result.isLeft()) {
+      return Optional.of(new NonPersistentCursor(context, system, result.getLeft()));
+    }
+
+    return Optional.absent();
+  }
+
+  @Override
+  public Optional<NonPersistentCursor> resetAndGetCursor(String jobId, String username) {
+    Inbox inbox = Inbox.create(system);
+    inbox.send(controller, new FetchResult(jobId, username));
+    Object receive = inbox.receive(Duration.create(1, TimeUnit.MINUTES));
+    Either<ActorRef, ActorRef> result = (Either<ActorRef, ActorRef>) receive;
+    if (result.isRight()) {
+      return Optional.absent();
+
+    } else if (result.isLeft()) {
+      // Reset the result set cursor
+      inbox.send(result.getLeft(), new ResetCursor());
+      Object resetResult = inbox.receive(Duration.create(1, TimeUnit.MINUTES));
+      if (resetResult instanceof CursorReset) {
+        return Optional.of(new NonPersistentCursor(context, system, result.getLeft()));
+      } else {
+        return Optional.absent();
+      }
+
+    }
+
+    return Optional.absent();
+  }
+
+    @Override
+    public Optional<AsyncExecutionFailed> getError(String jobId, String username) {
+        Inbox inbox = Inbox.create(system);
+        inbox.send(controller, new FetchError(jobId, username));
+        Object receive = inbox.receive(Duration.create(1, TimeUnit.MINUTES));
+        Optional<AsyncExecutionFailed>  result = (Optional<AsyncExecutionFailed>) receive;
+        return result;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ColumnDescription.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ColumnDescription.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ColumnDescription.java
new file mode 100644
index 0000000..c8dead6
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ColumnDescription.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.client;
+
+public interface ColumnDescription {
+  enum DataTypes {
+    TINYINT, //
+    SMALLINT, //
+    INT, //
+    BIGINT, //
+    BOOLEAN, //
+    FLOAT, //
+    DOUBLE, //
+    STRING, //
+    BINARY, // -- (Note: Available in Hive 0.8.0 and later)
+    TIMESTAMP, // -- (Note: Available in Hive 0.8.0 and later)
+    DECIMAL, // -- (Note: Available in Hive 0.11.0 and later)
+    // DECIMAL,(precision, scale)� -- (Note: Available in Hive 0.13.0 and later) Not included.
+    DATE, // -- (Note: Available in Hive 0.12.0 and later)
+    VARCHAR, // -- (Note: Available in Hive 0.12.0 and later)
+    CHAR, // -- (Note: Available in Hive 0.13.0 and later)
+  }
+
+  String getName();
+
+  String getType();
+
+  int getPosition();
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ColumnDescriptionExtended.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ColumnDescriptionExtended.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ColumnDescriptionExtended.java
new file mode 100644
index 0000000..b2f1e5e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ColumnDescriptionExtended.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.client;
+
+public class ColumnDescriptionExtended implements ColumnDescription {
+  private String name;
+  private String type;
+  private int position;
+  private String comment;
+  private boolean partitioned;
+  private boolean sortedBy;
+  private boolean clusteredBy;
+
+  public ColumnDescriptionExtended(String name, String type, String comment, boolean partitioned,
+                                   boolean sortedBy, boolean clusteredBy, int position) {
+    this.name = name;
+    this.type = type;
+    this.comment = comment;
+    this.partitioned = partitioned;
+    this.sortedBy = sortedBy;
+    this.clusteredBy = clusteredBy;
+    this.position = position;
+  }
+
+  public ColumnDescription createShortColumnDescription() {
+    return new ColumnDescriptionShort(getName(), getType(), getPosition());
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public int getPosition() {
+    return position;
+  }
+
+  public String getComment() {
+    return comment;
+  }
+
+  public boolean isPartitioned() {
+    return partitioned;
+  }
+
+  public boolean isSortedBy() {
+    return sortedBy;
+  }
+
+  public boolean isClusteredBy() {
+    return clusteredBy;
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ColumnDescriptionShort.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ColumnDescriptionShort.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ColumnDescriptionShort.java
new file mode 100644
index 0000000..928438c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ColumnDescriptionShort.java
@@ -0,0 +1,53 @@
+/**
+ * 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.ambari.view.hive2.client;
+
+import java.util.ArrayList;
+
+public class ColumnDescriptionShort extends ArrayList<Object> implements ColumnDescription {
+  private static final int INITIAL_CAPACITY = 3;
+  private String name;
+  private String type;
+  private int position;
+
+  public ColumnDescriptionShort(String name, String type, int position) {
+    super(INITIAL_CAPACITY);
+    add(name);
+    add(type);
+    add(position);
+    this.name = name;
+    this.type = type;
+    this.position = position;
+  }
+
+  @Override
+  public String getName() {
+    return name;
+  }
+
+  @Override
+  public String getType() {
+    return type;
+  }
+
+  @Override
+  public int getPosition() {
+    return position;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ConnectionConfig.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ConnectionConfig.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ConnectionConfig.java
new file mode 100644
index 0000000..4ae5577
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ConnectionConfig.java
@@ -0,0 +1,51 @@
+/*
+ * 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.ambari.view.hive2.client;
+
+import org.apache.ambari.view.hive2.actor.message.Connect;
+
+public class ConnectionConfig {
+  private final String username;
+  private final String password;
+  private final String jdbcUrl;
+
+  public ConnectionConfig(String username, String password, String jdbcUrl) {
+    this.username = username;
+    this.password = password;
+    this.jdbcUrl = jdbcUrl;
+  }
+
+  public String getUsername() {
+    return username;
+  }
+
+  public String getPassword() {
+    return password;
+  }
+
+  public String getJdbcUrl() {
+    return jdbcUrl;
+  }
+
+  public Connect createConnectMessage() {
+    return new Connect(username, password, jdbcUrl);
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/Cursor.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/Cursor.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/Cursor.java
new file mode 100644
index 0000000..6bf940d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/Cursor.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.client;
+
+import java.util.Iterator;
+import java.util.List;
+
+public interface Cursor<T, R> extends Iterator<T>, Iterable<T>{
+  boolean isResettable();
+  void reset();
+  int getOffset();
+  List<R> getDescriptions();
+  void keepAlive();
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/DDLDelegator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/DDLDelegator.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/DDLDelegator.java
new file mode 100644
index 0000000..20b91f1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/DDLDelegator.java
@@ -0,0 +1,36 @@
+/*
+ * 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.ambari.view.hive2.client;
+
+import java.util.List;
+
+public interface DDLDelegator {
+
+  List<String> getDbList(ConnectionConfig config, String like);
+
+  List<String> getTableList(ConnectionConfig config, String database, String like);
+
+  List<ColumnDescription> getTableDescription(ConnectionConfig config, String database, String table, String like, boolean extended);
+
+  Cursor<Row, ColumnDescription> getDbListCursor(ConnectionConfig config, String like);
+
+  Cursor<Row, ColumnDescription> getTableListCursor(ConnectionConfig config, String database, String like);
+
+  Cursor<Row, ColumnDescription> getTableDescriptionCursor(ConnectionConfig config, String database, String table, String like, boolean extended);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/DDLDelegatorImpl.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/DDLDelegatorImpl.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/DDLDelegatorImpl.java
new file mode 100644
index 0000000..52be70e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/DDLDelegatorImpl.java
@@ -0,0 +1,242 @@
+/*
+ * 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.ambari.view.hive2.client;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Inbox;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.utils.HiveActorConfiguration;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.apache.ambari.view.hive2.actor.message.Connect;
+import org.apache.ambari.view.hive2.actor.message.ExecuteJob;
+import org.apache.ambari.view.hive2.actor.message.GetColumnMetadataJob;
+import org.apache.ambari.view.hive2.actor.message.HiveJob;
+import org.apache.ambari.view.hive2.actor.message.SyncJob;
+import org.apache.ambari.view.hive2.actor.message.job.ExecutionFailed;
+import org.apache.ambari.view.hive2.actor.message.job.FetchFailed;
+import org.apache.ambari.view.hive2.actor.message.job.Next;
+import org.apache.ambari.view.hive2.actor.message.job.NoMoreItems;
+import org.apache.ambari.view.hive2.actor.message.job.NoResult;
+import org.apache.ambari.view.hive2.actor.message.job.Result;
+import org.apache.ambari.view.hive2.actor.message.job.ResultSetHolder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.concurrent.duration.Duration;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public class DDLDelegatorImpl implements DDLDelegator {
+
+  public static final String NO_VALUE_MARKER = "NO_VALUE";
+  private final Logger LOG = LoggerFactory.getLogger(getClass());
+
+  private final ActorRef controller;
+  private final ActorSystem system;
+
+  private final ViewContext context;
+  private final HiveActorConfiguration actorConfiguration;
+
+  public DDLDelegatorImpl(ViewContext context, ActorSystem system, ActorRef controller) {
+    this.context = context;
+    this.system = system;
+    this.controller = controller;
+    actorConfiguration = new HiveActorConfiguration(context);
+  }
+
+  @Override
+  public List<String> getDbList(ConnectionConfig config, String like) {
+    Optional<Result> rowsFromDB = getRowsFromDB(config, getDatabaseListStatements(like));
+    return rowsFromDB.isPresent() ? getFirstColumnValues(rowsFromDB.get().getRows()) : Lists.<String>newArrayList();
+  }
+
+  @Override
+  public List<String> getTableList(ConnectionConfig config, String database, String like) {
+    Optional<Result> rowsFromDB = getRowsFromDB(config, getTableListStatements(database, like));
+    return rowsFromDB.isPresent() ? getFirstColumnValues(rowsFromDB.get().getRows()) : Lists.<String>newArrayList();
+  }
+
+  @Override
+  public List<ColumnDescription> getTableDescription(ConnectionConfig config, String database, String table, String like, boolean extended) {
+ Optional<Result> resultOptional = getTableDescription(config, database, table, like);
+    List<ColumnDescription> descriptions = new ArrayList<>();
+    if(resultOptional.isPresent()) {
+      for (Row row : resultOptional.get().getRows()) {
+        Object[] values = row.getRow();
+        String name = (String) values[3];
+        String type = (String) values[5];
+        int position = (Integer) values[16];
+        descriptions.add(new ColumnDescriptionShort(name, type, position));
+      }
+    }
+    return descriptions;
+  }
+
+  @Override
+  public Cursor<Row, ColumnDescription> getDbListCursor(ConnectionConfig config, String like) {
+    Optional<Result> rowsFromDB = getRowsFromDB(config, getDatabaseListStatements(like));
+    if (rowsFromDB.isPresent()) {
+      Result result = rowsFromDB.get();
+      return new PersistentCursor<>(result.getRows(), result.getColumns());
+    } else {
+      return new PersistentCursor<>(Lists.<Row>newArrayList(), Lists.<ColumnDescription>newArrayList());
+    }
+  }
+
+  @Override
+  public Cursor<Row, ColumnDescription> getTableListCursor(ConnectionConfig config, String database, String like) {
+    Optional<Result> rowsFromDB = getRowsFromDB(config, getTableListStatements(database, like));
+    if (rowsFromDB.isPresent()) {
+      Result result = rowsFromDB.get();
+      return new PersistentCursor<>(result.getRows(), result.getColumns());
+    } else {
+      return new PersistentCursor<>(Lists.<Row>newArrayList(), Lists.<ColumnDescription>newArrayList());
+    }
+  }
+
+  @Override
+  public Cursor<Row, ColumnDescription> getTableDescriptionCursor(ConnectionConfig config, String database, String table, String like, boolean extended) {
+    Optional<Result> tableDescriptionOptional = getTableDescription(config, database, table, like);
+    if(tableDescriptionOptional.isPresent()) {
+      Result result = tableDescriptionOptional.get();
+      return new PersistentCursor<>(result.getRows(), result.getColumns());
+    } else {
+      return new PersistentCursor<>(Lists.<Row>newArrayList(), Lists.<ColumnDescription>newArrayList());
+    }
+  }
+
+  private String[] getDatabaseListStatements(String like) {
+    return new String[]{
+      String.format("show databases like '%s'", like)
+    };
+  }
+
+  private String[] getTableListStatements(String database, String like) {
+    return new String[]{
+      String.format("use %s", database),
+      String.format("show tables like '%s'", like)
+    };
+  }
+
+  private Optional<Result> getRowsFromDB(ConnectionConfig config, String[] statements) {
+    Connect connect = config.createConnectMessage();
+    HiveJob job = new SyncJob(config.getUsername(), statements, context);
+    ExecuteJob execute = new ExecuteJob(connect, job);
+
+    LOG.info("Executing query: {}, for user: {}", getJoinedStatements(statements), job.getUsername());
+
+    return getResultFromDB(execute);
+  }
+
+  private Optional<Result> getTableDescription(ConnectionConfig config, String databasePattern, String tablePattern, String columnPattern) {
+    Connect connect = config.createConnectMessage();
+    HiveJob job = new GetColumnMetadataJob(config.getUsername(), context, databasePattern, tablePattern, columnPattern);
+    ExecuteJob execute = new ExecuteJob(connect, job);
+
+    LOG.info("Executing query to fetch the column description for dbPattern: {}, tablePattern: {}, columnPattern: {}, for user: {}",
+      databasePattern, tablePattern, columnPattern, job.getUsername());
+    return getResultFromDB(execute);
+  }
+
+  private Optional<Result> getResultFromDB(ExecuteJob job) {
+    List<ColumnDescription> descriptions = null;
+    List<Row> rows = Lists.newArrayList();
+    Inbox inbox = Inbox.create(system);
+    inbox.send(controller, job);
+    Object submitResult;
+    try {
+      submitResult = inbox.receive(Duration.create(actorConfiguration.getSyncQueryTimeout(60 * 1000), TimeUnit.MILLISECONDS));
+    } catch (Throwable ex) {
+      String errorMessage = "Query timed out to fetch table description for user: " + job.getConnect().getUsername();
+      LOG.error(errorMessage, ex);
+      throw new ServiceFormattedException(errorMessage, ex);
+    }
+
+    if (submitResult instanceof NoResult) {
+      LOG.info("Query returned with no result.");
+      return Optional.absent();
+
+    }
+
+    if (submitResult instanceof ExecutionFailed) {
+      ExecutionFailed error = (ExecutionFailed) submitResult;
+      LOG.error("Failed to get the table description");
+      throw new ServiceFormattedException(error.getMessage(), error.getError());
+
+    } else if (submitResult instanceof ResultSetHolder) {
+      ResultSetHolder holder = (ResultSetHolder) submitResult;
+      ActorRef iterator = holder.getIterator();
+      while (true) {
+        inbox.send(iterator, new Next());
+        Object receive;
+        try {
+          receive = inbox.receive(Duration.create(actorConfiguration.getResultFetchTimeout(60 * 1000), TimeUnit.MILLISECONDS));
+        } catch (Throwable ex) {
+          String errorMessage = "Query timed out to fetch results for user: " + job.getConnect().getUsername();
+          LOG.error(errorMessage, ex);
+          throw new ServiceFormattedException(errorMessage, ex);
+        }
+
+        if (receive instanceof Result) {
+          Result result = (Result) receive;
+          if (descriptions == null) {
+            descriptions = result.getColumns();
+          }
+          rows.addAll(result.getRows());
+        }
+
+        if (receive instanceof NoMoreItems) {
+          break;
+        }
+
+        if (receive instanceof FetchFailed) {
+          FetchFailed error = (FetchFailed) receive;
+          LOG.error("Failed to fetch results ");
+          throw new ServiceFormattedException(error.getMessage(), error.getError());
+        }
+      }
+
+    }
+    return Optional.of(new Result(rows, descriptions));
+  }
+
+  private String getJoinedStatements(String[] statements) {
+    return Joiner.on("; ").skipNulls().join(statements);
+  }
+
+  private ImmutableList<String> getFirstColumnValues(List<Row> rows) {
+    return FluentIterable.from(rows)
+      .transform(new Function<Row, String>() {
+        @Override
+        public String apply(Row input) {
+          Object[] values = input.getRow();
+          return values.length > 0 ? (String) values[0] : NO_VALUE_MARKER;
+        }
+      }).toList();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/EmptyCursor.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/EmptyCursor.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/EmptyCursor.java
new file mode 100644
index 0000000..bf9d005
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/EmptyCursor.java
@@ -0,0 +1,110 @@
+/*
+ * 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.ambari.view.hive2.client;
+
+import com.beust.jcommander.internal.Lists;
+import org.apache.commons.lang.NotImplementedException;
+
+import java.util.Iterator;
+import java.util.List;
+
+public class EmptyCursor implements Cursor<Row, ColumnDescription> {
+
+    private List<Row> rows = Lists.newArrayList();
+    private List<ColumnDescription> desc = Lists.newArrayList();
+
+
+    @Override
+    public boolean isResettable() {
+        return false;
+    }
+
+    @Override
+    public void reset() {
+
+    }
+
+    @Override
+    public int getOffset() {
+        return 0;
+    }
+
+    @Override
+    public List<ColumnDescription> getDescriptions() {
+        return desc;
+    }
+
+  @Override
+  public void keepAlive() {
+    // Do Nothing
+  }
+
+  /**
+     * Returns an iterator over a set of elements of type T.
+     *
+     * @return an Iterator.
+     */
+    @Override
+    public Iterator<Row> iterator() {
+        return rows.iterator();
+    }
+
+    /**
+     * Returns {@code true} if the iteration has more elements.
+     * (In other words, returns {@code true} if {@link #next} would
+     * return an element rather than throwing an exception.)
+     *
+     * @return {@code true} if the iteration has more elements
+     */
+    @Override
+    public boolean hasNext() {
+        return false;
+    }
+
+    /**
+     * Returns the next element in the iteration.
+     *
+     * @return the next element in the iteration
+     * @throws NotImplementedException  if the iteration has no more elements
+     */
+    @Override
+    public Row next() {
+        throw new NotImplementedException();
+    }
+
+    /**
+     * Removes from the underlying collection the last element returned
+     * by this iterator (optional operation).  This method can be called
+     * only once per call to {@link #next}.  The behavior of an iterator
+     * is unspecified if the underlying collection is modified while the
+     * iteration is in progress in any way other than by calling this
+     * method.
+     *
+     * @throws UnsupportedOperationException if the {@code remove}
+     *                                       operation is not supported by this iterator
+     * @throws IllegalStateException         if the {@code next} method has not
+     *                                       yet been called, or the {@code remove} method has already
+     *                                       been called after the last call to the {@code next}
+     *                                       method
+     */
+    @Override
+    public void remove() {
+        throw new NotImplementedException();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveAuthCredentials.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveAuthCredentials.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveAuthCredentials.java
new file mode 100644
index 0000000..5350d55
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveAuthCredentials.java
@@ -0,0 +1,31 @@
+/**
+ * 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.ambari.view.hive2.client;
+
+public class HiveAuthCredentials {
+  private String password;
+
+  public String getPassword() {
+    return password;
+  }
+
+  public void setPassword(String password) {
+    this.password = password;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveAuthRequiredException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveAuthRequiredException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveAuthRequiredException.java
new file mode 100644
index 0000000..db0c762
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveAuthRequiredException.java
@@ -0,0 +1,27 @@
+/**
+ * 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.ambari.view.hive2.client;
+
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+
+public class HiveAuthRequiredException extends ServiceFormattedException {
+  public HiveAuthRequiredException() {
+    super("Hive Password Required", null, 401);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveClientAuthRequiredException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveClientAuthRequiredException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveClientAuthRequiredException.java
new file mode 100644
index 0000000..94ff709
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveClientAuthRequiredException.java
@@ -0,0 +1,25 @@
+/**
+ * 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.ambari.view.hive2.client;
+
+public class HiveClientAuthRequiredException extends Exception {
+  public HiveClientAuthRequiredException(String comment, Exception ex) {
+    super(comment + ((ex == null)?"":(": " + ex.toString())), ex);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveClientException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveClientException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveClientException.java
new file mode 100644
index 0000000..4d8ee01
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveClientException.java
@@ -0,0 +1,25 @@
+/**
+ * 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.ambari.view.hive2.client;
+
+public class HiveClientException extends Exception {
+  public HiveClientException(String comment, Exception ex) {
+    super(comment + ((ex == null)?"":(": " + ex.toString())), ex);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveClientRuntimeException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveClientRuntimeException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveClientRuntimeException.java
new file mode 100644
index 0000000..f2bb4c3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/HiveClientRuntimeException.java
@@ -0,0 +1,25 @@
+/**
+ * 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.ambari.view.hive2.client;
+
+public class HiveClientRuntimeException extends RuntimeException {
+  public HiveClientRuntimeException(String comment, Exception ex) {
+    super(comment + ((ex == null)?"":(": " + ex.toString())), ex);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/NonPersistentCursor.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/NonPersistentCursor.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/NonPersistentCursor.java
new file mode 100644
index 0000000..ef015dc
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/NonPersistentCursor.java
@@ -0,0 +1,153 @@
+/*
+ * 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.ambari.view.hive2.client;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Inbox;
+import com.google.common.collect.Lists;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.actor.message.lifecycle.KeepAlive;
+import org.apache.ambari.view.hive2.utils.HiveActorConfiguration;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.apache.ambari.view.hive2.actor.message.job.FetchFailed;
+import org.apache.ambari.view.hive2.actor.message.job.Next;
+import org.apache.ambari.view.hive2.actor.message.job.NoMoreItems;
+import org.apache.ambari.view.hive2.actor.message.job.Result;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.concurrent.duration.Duration;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Wrapper over iterator actor and blocks to fetch Rows and ColumnDescription whenever there is no more Rows to be
+ * returned.
+ */
+public class NonPersistentCursor implements Cursor<Row, ColumnDescription> {
+  private final Logger LOG = LoggerFactory.getLogger(getClass());
+  private static long DEFAULT_WAIT_TIMEOUT = 60 * 1000L;
+
+  private final ActorSystem system;
+  private final ActorRef actorRef;
+  private final ViewContext context;
+  private final HiveActorConfiguration actorConfiguration;
+  private final Queue<Row> rows = Lists.newLinkedList();
+  private final List<ColumnDescription> descriptions = Lists.newLinkedList();
+  private int offSet = 0;
+  private boolean endReached = false;
+
+
+  public NonPersistentCursor(ViewContext context, ActorSystem system, ActorRef actorRef) {
+    this.context = context;
+    this.system = system;
+    this.actorRef = actorRef;
+    actorConfiguration = new HiveActorConfiguration(context);
+  }
+
+  @Override
+  public boolean isResettable() {
+    return false;
+  }
+
+  @Override
+  public void reset() {
+    // Do nothing
+  }
+
+  @Override
+  public int getOffset() {
+    return offSet;
+  }
+
+  @Override
+  public List<ColumnDescription> getDescriptions() {
+    fetchIfNeeded();
+    return descriptions;
+  }
+
+  @Override
+  public void keepAlive() {
+    Inbox inbox = Inbox.create(system);
+    inbox.send(actorRef, new KeepAlive());
+  }
+
+  @Override
+  public Iterator<Row> iterator() {
+    return this;
+  }
+
+  @Override
+  public boolean hasNext() {
+    fetchIfNeeded();
+    return !endReached;
+  }
+
+  @Override
+  public Row next() {
+    fetchIfNeeded();
+    offSet++;
+    return rows.poll();
+  }
+
+  @Override
+  public void remove() {
+    throw new RuntimeException("Read only cursor. Method not supported");
+  }
+
+  private void fetchIfNeeded() {
+    if (endReached || rows.size() > 0) return;
+    getNextRows();
+  }
+
+  private void getNextRows() {
+    Inbox inbox = Inbox.create(system);
+    inbox.send(actorRef, new Next());
+    Object receive;
+    try {
+      receive = inbox.receive(Duration.create(actorConfiguration.getResultFetchTimeout(DEFAULT_WAIT_TIMEOUT),
+        TimeUnit.MILLISECONDS));
+    } catch (Throwable ex) {
+      String errorMessage = "Result fetch timed out";
+      LOG.error(errorMessage, ex);
+      throw new ServiceFormattedException(errorMessage, ex);
+    }
+
+    if (receive instanceof Result) {
+      Result result = (Result) receive;
+      if (descriptions.isEmpty()) {
+        descriptions.addAll(result.getColumns());
+      }
+      rows.addAll(result.getRows());
+    }
+
+    if (receive instanceof NoMoreItems) {
+      endReached = true;
+    }
+
+    if (receive instanceof FetchFailed) {
+      FetchFailed error = (FetchFailed) receive;
+      LOG.error("Failed to fetch results ");
+      throw new ServiceFormattedException(error.getMessage(), error.getError());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/PersistentCursor.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/PersistentCursor.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/PersistentCursor.java
new file mode 100644
index 0000000..aadf31c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/PersistentCursor.java
@@ -0,0 +1,87 @@
+/*
+ * 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.ambari.view.hive2.client;
+
+
+import com.google.common.collect.Lists;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Wrapper over other iterables. Does not block and can be reset to start again from beginning.
+ */
+public class PersistentCursor<T, R> implements Cursor<T, R>  {
+  private List<T> rows = Lists.newArrayList();
+  private List<R> columns = Lists.newArrayList();
+  private int offset = 0;
+
+  public PersistentCursor(List<T> rows, List<R> columns) {
+    this.rows = rows;
+    this.columns = columns;
+  }
+
+
+  @Override
+  public Iterator<T> iterator() {
+    return this;
+  }
+
+  @Override
+  public boolean hasNext() {
+    return rows.size() > 0 && offset < rows.size();
+  }
+
+  @Override
+  public T next() {
+    T row = rows.get(offset);
+    offset++;
+    return row;
+  }
+
+  @Override
+  public void remove() {
+    throw new RuntimeException("Read only cursor. Method not supported");
+  }
+
+  @Override
+  public boolean isResettable() {
+    return true;
+  }
+
+  @Override
+  public void reset() {
+    this.offset = 0;
+  }
+
+  @Override
+  public int getOffset() {
+    return offset;
+  }
+
+  @Override
+  public List<R> getDescriptions() {
+    return columns;
+  }
+
+  @Override
+  public void keepAlive() {
+    // Do Nothing as we are pre-fetching everything.
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/Row.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/Row.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/Row.java
new file mode 100644
index 0000000..0faa6c7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/Row.java
@@ -0,0 +1,74 @@
+/**
+ * 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.ambari.view.hive2.client;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+public class Row {
+  private Object[] row;
+
+  public Row(Object[] row) {
+    this(row, null);
+  }
+
+  public Row(Object[] row, HashSet<Integer> selectedColumns) {
+    if (selectedColumns == null || selectedColumns.size() == 0)
+      this.row = row.clone();
+    else {
+      this.row = new Object[selectedColumns.size()];
+      int rowIndex = 0;
+      for (Integer selectedIndex : selectedColumns) {
+        this.row[rowIndex] = row[selectedIndex];
+        rowIndex ++;
+      }
+    }
+  }
+
+  public Object[] getRow() {
+    return row;
+  }
+
+  public void setRow(Object[] row) {
+    this.row = row;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    Row row1 = (Row) o;
+
+    boolean retValue = Arrays.equals(row, row1.row);
+    return retValue;
+  }
+
+  @Override
+  public int hashCode() {
+    return Arrays.hashCode(row);
+  }
+
+  @Override
+  public String toString() {
+    return "Row{" +
+            "row=" + Arrays.toString(row) +
+            '}';
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/exceptions/NotConnectedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/exceptions/NotConnectedException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/exceptions/NotConnectedException.java
new file mode 100644
index 0000000..71e64d2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/exceptions/NotConnectedException.java
@@ -0,0 +1,28 @@
+/*
+ * 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.ambari.view.hive2.exceptions;
+
+/**
+ * Exception thrown when the connection is not made and we try to execute some job
+ */
+public class NotConnectedException extends RuntimeException {
+  public NotConnectedException(String message) {
+    super(message);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/AsyncExecutionFailure.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/AsyncExecutionFailure.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/AsyncExecutionFailure.java
new file mode 100644
index 0000000..f587ce0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/AsyncExecutionFailure.java
@@ -0,0 +1,23 @@
+/*
+ * 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.ambari.view.hive2.internal;
+
+public class AsyncExecutionFailure {
+}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/AsyncExecutionSuccess.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/AsyncExecutionSuccess.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/AsyncExecutionSuccess.java
new file mode 100644
index 0000000..c45b303
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/AsyncExecutionSuccess.java
@@ -0,0 +1,25 @@
+/*
+ * 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.ambari.view.hive2.internal;
+
+public class AsyncExecutionSuccess {
+
+
+}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Connectable.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Connectable.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Connectable.java
new file mode 100644
index 0000000..5bfb6dc
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Connectable.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.internal;
+
+import com.google.common.base.Optional;
+import org.apache.hive.jdbc.HiveConnection;
+
+/**
+ * Life cycle management for java.sql.Connection
+ */
+public interface Connectable  {
+
+    /**
+     * Get the underlying connection
+     * @return an optional wrapping the connection
+     */
+    Optional<HiveConnection> getConnection();
+
+    /**
+     * Check if the connection is open
+     * @return
+     */
+    boolean isOpen();
+
+    /**
+     * Open a connection
+     * @throws ConnectionException
+     */
+    void connect() throws ConnectionException;
+
+    /**
+     * Reconnect if closed
+     * @throws ConnectionException
+     */
+    void reconnect() throws ConnectionException;
+
+    /**
+     * Close the connection
+     * @throws ConnectionException
+     */
+    void disconnect() throws ConnectionException;
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ConnectionException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ConnectionException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ConnectionException.java
new file mode 100644
index 0000000..14db3f1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ConnectionException.java
@@ -0,0 +1,25 @@
+/*
+ * 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.ambari.view.hive2.internal;
+
+public class ConnectionException extends Exception {
+    public ConnectionException(Exception e, String message) {
+        super(message,e);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ConnectionProperties.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ConnectionProperties.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ConnectionProperties.java
new file mode 100644
index 0000000..6f829c3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ConnectionProperties.java
@@ -0,0 +1,94 @@
+/*
+ * 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.ambari.view.hive2.internal;
+
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+
+/**
+ * Holds all information needed to connect to HS2
+ */
+public class ConnectionProperties {
+
+    private String host;
+    private int port;
+    private String userName;
+    private String password;
+    private Map<String, String> authParams = Maps.newHashMap();
+
+    public Map<String, String> getAuthParams() {
+        return authParams;
+    }
+
+    public void addAuthParam(String key,String value){
+        authParams.put(key, value);
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    @Override
+    public String toString() {
+        return "HiveConnectionProps{" +
+                "authParams=" + authParams +
+                ", host='" + host + '\'' +
+                ", port=" + port +
+                ", userName='" + userName + '\'' +
+                ", password='" + password + '\'' +
+                '}';
+    }
+
+    public String asUrl() {
+        return null;
+    }
+
+    public String asUrlWithoutCredentials() {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ConnectionSupplier.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ConnectionSupplier.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ConnectionSupplier.java
new file mode 100644
index 0000000..3cc268b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ConnectionSupplier.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.internal;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.ConnectionDelegate;
+import org.apache.ambari.view.hive2.HiveJdbcConnectionDelegate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConnectionSupplier implements ContextSupplier<ConnectionDelegate> {
+
+  protected final Logger LOG =
+    LoggerFactory.getLogger(getClass());
+
+  @Override
+  public ConnectionDelegate get(ViewContext context) {
+    LOG.debug("Creating Connection delegate instance for Viewname: {}, Instance Name: {}", context.getViewName(), context.getInstanceName());
+    return new HiveJdbcConnectionDelegate();
+  }
+}


[02/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/dagre.min.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/dagre.min.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/dagre.min.js
new file mode 100644
index 0000000..10a0471
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/dagre.min.js
@@ -0,0 +1,27 @@
+/**
+ * @license
+ * Copyright (c) 2012-2014 Chris Pettitt
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){(function(global){global.dagre=require("./index");global.dagre.graphlib=require("graphlib")}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{})},{"./index":2,graphlib:29}],2:[function(require,module,exports){module.exports={layout:require("./lib/layout"),debug:require("./lib/debug"),util:{time:require("./lib/util").time,notime:require("./lib/util").notime},version:require("./lib/version")}},{"./lib/debug":6,"./lib/layout":8,"./lib/util":27,"./lib/v
 ersion":28}],3:[function(require,module,exports){"use strict";var _=require("lodash"),greedyFAS=require("./greedy-fas");module.exports={run:run,undo:undo};function run(g){var fas=g.graph().acyclicer==="greedy"?greedyFAS(g,weightFn(g)):dfsFAS(g);_.each(fas,function(e){var label=g.edge(e);g.removeEdge(e);label.forwardName=e.name;label.reversed=true;g.setEdge(e.w,e.v,label,_.uniqueId("rev"))});function weightFn(g){return function(e){return g.edge(e).weight}}}function dfsFAS(g){var fas=[],stack={},visited={};function dfs(v){if(_.has(visited,v)){return}visited[v]=true;stack[v]=true;_.each(g.outEdges(v),function(e){if(_.has(stack,e.w)){fas.push(e)}else{dfs(e.w)}});delete stack[v]}_.each(g.nodes(),dfs);return fas}function undo(g){_.each(g.edges(),function(e){var label=g.edge(e);if(label.reversed){g.removeEdge(e);var forwardName=label.forwardName;delete label.reversed;delete label.forwardName;g.setEdge(e.w,e.v,label,forwardName)}})}},{"./greedy-fas":7,lodash:48}],4:[function(require,module,
 exports){var _=require("lodash"),util=require("./util");module.exports=addBorderSegments;function addBorderSegments(g){function dfs(v){var children=g.children(v),node=g.node(v);if(children.length){_.each(children,dfs)}if(_.has(node,"minRank")){node.borderLeft=[];node.borderRight=[];for(var rank=node.minRank,maxRank=node.maxRank+1;rank<maxRank;++rank){addBorderNode(g,"borderLeft","_bl",v,node,rank);addBorderNode(g,"borderRight","_br",v,node,rank)}}}_.each(g.children(),dfs)}function addBorderNode(g,prop,prefix,sg,sgNode,rank){var label={width:0,height:0,rank:rank},prev=sgNode[prop][rank-1],curr=util.addDummyNode(g,"border",label,prefix);sgNode[prop][rank]=curr;g.setParent(curr,sg);if(prev){g.setEdge(prev,curr,{weight:1})}}},{"./util":27,lodash:48}],5:[function(require,module,exports){module.exports=List;function List(){var sentinel={};sentinel._next=sentinel._prev=sentinel;this._sentinel=sentinel}List.prototype.dequeue=function(){var sentinel=this._sentinel,entry=sentinel._prev;if(ent
 ry!==sentinel){unlink(entry);return entry}};List.prototype.enqueue=function(entry){var sentinel=this._sentinel;if(entry._prev&&entry._next){unlink(entry)}entry._next=sentinel._next;sentinel._next._prev=entry;sentinel._next=entry;entry._prev=sentinel};List.prototype.toString=function(){var strs=[],sentinel=this._sentinel,curr=sentinel._prev;while(curr!==sentinel){strs.push(JSON.stringify(curr,filterOutLinks));curr=curr._prev}return"["+strs.join(", ")+"]"};function unlink(entry){entry._prev._next=entry._next;entry._next._prev=entry._prev;delete entry._next;delete entry._prev}function filterOutLinks(k,v){if(k!=="_next"&&k!=="_prev"){return v}}},{}],6:[function(require,module,exports){var _=require("lodash"),util=require("./util"),Graph=require("graphlib").Graph;module.exports={debugOrdering:debugOrdering};function debugOrdering(g){var layerMatrix=util.buildLayerMatrix(g);var h=new Graph({compound:true,multigraph:true}).setGraph({});_.each(g.nodes(),function(v){h.setNode(v,{label:v});h.
 setParent(v,"layer"+g.node(v).rank)});_.each(g.edges(),function(e){h.setEdge(e.v,e.w,{},e.name)});_.each(layerMatrix,function(layer,i){var layerV="layer"+i;h.setNode(layerV,{rank:"same"});_.reduce(layer,function(u,v){h.setEdge(u,v,{style:"invis"});return v})});return h}},{"./util":27,graphlib:29,lodash:48}],7:[function(require,module,exports){var _=require("lodash"),Graph=require("graphlib").Graph,List=require("./data/list");module.exports=greedyFAS;var DEFAULT_WEIGHT_FN=_.constant(1);function greedyFAS(g,weightFn){if(g.nodeCount()<=1){return[]}var state=buildState(g,weightFn||DEFAULT_WEIGHT_FN);var results=doGreedyFAS(state.graph,state.buckets,state.zeroIdx);return _.flatten(_.map(results,function(e){return g.outEdges(e.v,e.w)}),true)}function doGreedyFAS(g,buckets,zeroIdx){var results=[],sources=buckets[buckets.length-1],sinks=buckets[0];var entry;while(g.nodeCount()){while(entry=sinks.dequeue()){removeNode(g,buckets,zeroIdx,entry)}while(entry=sources.dequeue()){removeNode(g,bucke
 ts,zeroIdx,entry)}if(g.nodeCount()){for(var i=buckets.length-2;i>0;--i){entry=buckets[i].dequeue();if(entry){results=results.concat(removeNode(g,buckets,zeroIdx,entry,true));break}}}}return results}function removeNode(g,buckets,zeroIdx,entry,collectPredecessors){var results=collectPredecessors?[]:undefined;_.each(g.inEdges(entry.v),function(edge){var weight=g.edge(edge),uEntry=g.node(edge.v);if(collectPredecessors){results.push({v:edge.v,w:edge.w})}uEntry.out-=weight;assignBucket(buckets,zeroIdx,uEntry)});_.each(g.outEdges(entry.v),function(edge){var weight=g.edge(edge),w=edge.w,wEntry=g.node(w);wEntry.in-=weight;assignBucket(buckets,zeroIdx,wEntry)});g.removeNode(entry.v);return results}function buildState(g,weightFn){var fasGraph=new Graph,maxIn=0,maxOut=0;_.each(g.nodes(),function(v){fasGraph.setNode(v,{v:v,"in":0,out:0})});_.each(g.edges(),function(e){var prevWeight=fasGraph.edge(e.v,e.w)||0,weight=weightFn(e),edgeWeight=prevWeight+weight;fasGraph.setEdge(e.v,e.w,edgeWeight);max
 Out=Math.max(maxOut,fasGraph.node(e.v).out+=weight);maxIn=Math.max(maxIn,fasGraph.node(e.w).in+=weight)});var buckets=_.range(maxOut+maxIn+3).map(function(){return new List});var zeroIdx=maxIn+1;_.each(fasGraph.nodes(),function(v){assignBucket(buckets,zeroIdx,fasGraph.node(v))});return{graph:fasGraph,buckets:buckets,zeroIdx:zeroIdx}}function assignBucket(buckets,zeroIdx,entry){if(!entry.out){buckets[0].enqueue(entry)}else if(!entry.in){buckets[buckets.length-1].enqueue(entry)}else{buckets[entry.out-entry.in+zeroIdx].enqueue(entry)}}},{"./data/list":5,graphlib:29,lodash:48}],8:[function(require,module,exports){"use strict";var _=require("lodash"),acyclic=require("./acyclic"),normalize=require("./normalize"),rank=require("./rank"),normalizeRanks=require("./util").normalizeRanks,parentDummyChains=require("./parent-dummy-chains"),removeEmptyRanks=require("./util").removeEmptyRanks,nestingGraph=require("./nesting-graph"),addBorderSegments=require("./add-border-segments"),order=require(".
 /order"),position=require("./position"),util=require("./util"),Graph=require("graphlib").Graph;module.exports=layout;function layout(g,opts){var time=opts&&opts.debugTiming?util.time:util.notime;time("layout",function(){var layoutGraph=time("  buildLayoutGraph",function(){return buildLayoutGraph(g)});time("  runLayout",function(){runLayout(layoutGraph,time)});time("  updateInputGraph",function(){updateInputGraph(g,layoutGraph)})})}function runLayout(g,time){time("    makeSpaceForEdgeLabels",function(){makeSpaceForEdgeLabels(g)});time("    removeSelfEdges",function(){removeSelfEdges(g)});time("    acyclic",function(){acyclic.run(g)});time("    nestingGraph.run",function(){nestingGraph.run(g)});time("    rank",function(){rank(util.asNonCompoundGraph(g))});time("    injectEdgeLabelProxies",function(){injectEdgeLabelProxies(g)});time("    removeEmptyRanks",function(){removeEmptyRanks(g)});time("    nestingGraph.cleanup",function(){nestingGraph.cleanup(g)});time("    normalizeRanks",func
 tion(){normalizeRanks(g)});time("    assignRankMinMax",function(){assignRankMinMax(g)});time("    removeEdgeLabelProxies",function(){removeEdgeLabelProxies(g)});time("    normalize.run",function(){normalize.run(g)});time("    parentDummyChains",function(){parentDummyChains(g)});time("    addBorderSegments",function(){addBorderSegments(g)});time("    order",function(){order(g)});time("    insertSelfEdges",function(){insertSelfEdges(g)});time("    position",function(){position(g)});time("    positionSelfEdges",function(){positionSelfEdges(g)});time("    setGraphDimensions",function(){setGraphDimensions(g)});time("    removeBorderNodes",function(){removeBorderNodes(g)});time("    normalize.undo",function(){normalize.undo(g)});time("    assignNodeIntersects",function(){assignNodeIntersects(g)});time("    reversePoints",function(){reversePointsForReversedEdges(g)});time("    acyclic.undo",function(){acyclic.undo(g)})}function updateInputGraph(inputGraph,layoutGraph){_.each(inputGraph.nod
 es(),function(v){var inputLabel=inputGraph.node(v),layoutLabel=layoutGraph.node(v);if(inputLabel){inputLabel.x=layoutLabel.x;inputLabel.y=layoutLabel.y;if(layoutGraph.children(v).length){inputLabel.width=layoutLabel.width;inputLabel.height=layoutLabel.height}}});_.each(inputGraph.edges(),function(e){var inputLabel=inputGraph.edge(e),layoutLabel=layoutGraph.edge(e);inputLabel.points=layoutLabel.points;if(_.has(layoutLabel,"x")){inputLabel.x=layoutLabel.x;inputLabel.y=layoutLabel.y}});inputGraph.graph().width=layoutGraph.graph().width;inputGraph.graph().height=layoutGraph.graph().height}var graphNumAttrs=["nodesep","edgesep","ranksep","marginx","marginy"],graphDefaults={ranksep:50,edgesep:10,nodesep:50},graphAttrs=["acyclicer","ranker","rankdir","align"],nodeNumAttrs=["width","height"],nodeDefaults={width:0,height:0},edgeNumAttrs=["minlen","weight","width","height"],edgeDefaults={minlen:1,weight:1,width:0,height:0};function buildLayoutGraph(inputGraph){var g=new Graph({multigraph:true
 ,compound:true});g.setGraph(_.merge({},graphDefaults,selectNumberAttrs(inputGraph.graph(),graphNumAttrs),_.pick(inputGraph.graph(),graphAttrs)));_.each(inputGraph.nodes(),function(v){var label=inputGraph.node(v);g.setNode(v,_.defaults(selectNumberAttrs(label,nodeNumAttrs),nodeDefaults));g.setParent(v,inputGraph.parent(v))});_.each(inputGraph.edges(),function(e){var label=inputGraph.edge(e);g.setEdge(e,_.defaults(selectNumberAttrs(label,edgeNumAttrs),edgeDefaults))});return g}function makeSpaceForEdgeLabels(g){var graphLabel=g.graph();graphLabel.ranksep/=2;_.each(g.edges(),function(e){g.edge(e).minlen*=2})}function injectEdgeLabelProxies(g){_.each(g.edges(),function(e){var edge=g.edge(e);if(edge.width&&edge.height){var v=g.node(e.v),w=g.node(e.w),label={rank:(w.rank-v.rank)/2+v.rank,e:e};util.addDummyNode(g,"edge-proxy",label,"_ep")}})}function assignRankMinMax(g){var maxRank=0;_.each(g.nodes(),function(v){var node=g.node(v);if(node.borderTop){node.minRank=g.node(node.borderTop).rank
 ;node.maxRank=g.node(node.borderBottom).rank;maxRank=_.max(maxRank,node.maxRank)}});g.graph().maxRank=maxRank}function removeEdgeLabelProxies(g){_.each(g.nodes(),function(v){var node=g.node(v);if(node.dummy==="edge-proxy"){g.edge(node.e).labelRank=node.rank;g.removeNode(v)}})}function setGraphDimensions(g){var width=0,height=0,graph=g.graph();_.each(g.nodes(),function(v){var node=g.node(v);width=Math.max(width,node.x+node.width/2);height=Math.max(height,node.y+node.height/2)});graph.width=width;graph.height=height}function assignNodeIntersects(g){_.each(g.edges(),function(e){var edge=g.edge(e),nodeV=g.node(e.v),nodeW=g.node(e.w),p1,p2;if(!edge.points){edge.points=[];p1=nodeW;p2=nodeV}else{p1=edge.points[0];p2=edge.points[edge.points.length-1]}edge.points.unshift(util.intersectRect(nodeV,p1));edge.points.push(util.intersectRect(nodeW,p2))})}function reversePointsForReversedEdges(g){_.each(g.edges(),function(e){var edge=g.edge(e);if(edge.reversed){edge.points.reverse()}})}function rem
 oveBorderNodes(g){var rankdir=(g.graph().rankdir||"tb").toLowerCase();_.each(g.nodes(),function(v){if(g.children(v).length){var node=g.node(v),t=g.node(node.borderTop),b=g.node(node.borderBottom),l=g.node(_.last(node.borderLeft)),r=g.node(_.last(node.borderRight)),tmp;if(rankdir==="bt"||rankdir==="rl"){tmp=t;t=b;b=tmp}if(rankdir==="lr"||rankdir==="rl"){tmp=t;t=l;l=tmp;tmp=b;b=r;r=tmp}node.width=r.x-l.x;node.height=b.y-t.y;node.x=l.x+node.width/2;node.y=t.y+node.height/2}});_.each(g.nodes(),function(v){if(g.node(v).dummy==="border"){g.removeNode(v)}})}function removeSelfEdges(g){_.each(g.edges(),function(e){if(e.v===e.w){var node=g.node(e.v);if(!node.selfEdges){node.selfEdges=[]}node.selfEdges.push({e:e,label:g.edge(e)});g.removeEdge(e)}})}function insertSelfEdges(g){var layers=util.buildLayerMatrix(g);_.each(layers,function(layer){var orderShift=0;_.each(layer,function(v,i){var node=g.node(v);node.order=i+orderShift;_.each(node.selfEdges,function(selfEdge){util.addDummyNode(g,"selfe
 dge",{width:selfEdge.label.width,height:selfEdge.label.height,rank:node.rank,order:i+ ++orderShift,e:selfEdge.e,label:selfEdge.label},"_se")});delete node.selfEdges})})}function positionSelfEdges(g){_.each(g.nodes(),function(v){var node=g.node(v);if(node.dummy==="selfedge"){var selfNode=g.node(node.e.v),x=selfNode.x+selfNode.width/2,y=selfNode.y,dx=node.x-x,dy=selfNode.height/2;g.setEdge(node.e,node.label);g.removeNode(v);node.label.points=[{x:x+2*dx/3,y:y-dy},{x:x+5*dx/6,y:y-dy},{x:x+dx,y:y},{x:x+5*dx/6,y:y+dy},{x:x+2*dx/3,y:y+dy}];node.label.x=node.x;node.label.y=node.y}})}function selectNumberAttrs(obj,attrs){return _.mapValues(_.pick(obj,attrs),Number)}},{"./acyclic":3,"./add-border-segments":4,"./nesting-graph":9,"./normalize":10,"./order":15,"./parent-dummy-chains":20,"./position":22,"./rank":24,"./util":27,graphlib:29,lodash:48}],9:[function(require,module,exports){var _=require("lodash"),util=require("./util");module.exports={run:run,cleanup:cleanup};function run(g){var root
 =util.addDummyNode(g,"root",{},"_root"),depths=treeDepths(g),height=_.max(depths)-1,nodeSep=2*height+1;g.graph().nestingRoot=root;_.each(g.edges(),function(e){g.edge(e).minlen*=nodeSep});var weight=sumWeights(g)+1;_.each(g.children(),function(child){dfs(g,root,nodeSep,weight,height,depths,child)});g.graph().nodeRankFactor=nodeSep}function dfs(g,root,nodeSep,weight,height,depths,v){var children=g.children(v);if(!children.length){if(v!==root){g.setEdge(root,v,{weight:0,minlen:nodeSep})}return}var top=util.addBorderNode(g,"_bt"),bottom=util.addBorderNode(g,"_bb"),label=g.node(v);g.setParent(top,v);label.borderTop=top;g.setParent(bottom,v);label.borderBottom=bottom;_.each(children,function(child){dfs(g,root,nodeSep,weight,height,depths,child);var childNode=g.node(child),childTop=childNode.borderTop?childNode.borderTop:child,childBottom=childNode.borderBottom?childNode.borderBottom:child,thisWeight=childNode.borderTop?weight:2*weight,minlen=childTop!==childBottom?1:height-depths[v]+1;g.s
 etEdge(top,childTop,{weight:thisWeight,minlen:minlen,nestingEdge:true});g.setEdge(childBottom,bottom,{weight:thisWeight,minlen:minlen,nestingEdge:true})});if(!g.parent(v)){g.setEdge(root,top,{weight:0,minlen:height+depths[v]})}}function treeDepths(g){var depths={};function dfs(v,depth){var children=g.children(v);if(children&&children.length){_.each(children,function(child){dfs(child,depth+1)})}depths[v]=depth}_.each(g.children(),function(v){dfs(v,1)});return depths}function sumWeights(g){return _.reduce(g.edges(),function(acc,e){return acc+g.edge(e).weight},0)}function cleanup(g){var graphLabel=g.graph();g.removeNode(graphLabel.nestingRoot);delete graphLabel.nestingRoot;_.each(g.edges(),function(e){var edge=g.edge(e);if(edge.nestingEdge){g.removeEdge(e)}})}},{"./util":27,lodash:48}],10:[function(require,module,exports){"use strict";var _=require("lodash"),util=require("./util");module.exports={run:run,undo:undo};function run(g){g.graph().dummyChains=[];_.each(g.edges(),function(edge
 ){normalizeEdge(g,edge)})}function normalizeEdge(g,e){var v=e.v,vRank=g.node(v).rank,w=e.w,wRank=g.node(w).rank,name=e.name,edgeLabel=g.edge(e),labelRank=edgeLabel.labelRank;if(wRank===vRank+1)return;g.removeEdge(e);var dummy,attrs,i;for(i=0,++vRank;vRank<wRank;++i,++vRank){edgeLabel.points=[];attrs={width:0,height:0,edgeLabel:edgeLabel,edgeObj:e,rank:vRank};dummy=util.addDummyNode(g,"edge",attrs,"_d");if(vRank===labelRank){attrs.width=edgeLabel.width;attrs.height=edgeLabel.height;attrs.dummy="edge-label"}g.setEdge(v,dummy,{weight:edgeLabel.weight},name);if(i===0){g.graph().dummyChains.push(dummy)}v=dummy}g.setEdge(v,w,{weight:edgeLabel.weight},name)}function undo(g){_.each(g.graph().dummyChains,function(v){var node=g.node(v),origLabel=node.edgeLabel,w;g.setEdge(node.edgeObj,origLabel);while(node.dummy){w=g.successors(v)[0];g.removeNode(v);origLabel.points.push({x:node.x,y:node.y});if(node.dummy==="edge-label"){origLabel.x=node.x;origLabel.y=node.y}v=w;node=g.node(v)}})}},{"./util":
 27,lodash:48}],11:[function(require,module,exports){var _=require("lodash");module.exports=addSubgraphConstraints;function addSubgraphConstraints(g,cg,vs){var prev={},rootPrev;_.each(vs,function(v){var child=g.parent(v),parent,prevChild;while(child){parent=g.parent(child);if(parent){prevChild=prev[parent];prev[parent]=child}else{prevChild=rootPrev;rootPrev=child}if(prevChild&&prevChild!==child){cg.setEdge(prevChild,child);return}child=parent}})}},{lodash:48}],12:[function(require,module,exports){var _=require("lodash");module.exports=barycenter;function barycenter(g,movable){return _.map(movable,function(v){var inV=g.inEdges(v);if(!inV.length){return{v:v}}else{var result=_.reduce(inV,function(acc,e){var edge=g.edge(e),nodeU=g.node(e.v);return{sum:acc.sum+edge.weight*nodeU.order,weight:acc.weight+edge.weight}},{sum:0,weight:0});return{v:v,barycenter:result.sum/result.weight,weight:result.weight}}})}},{lodash:48}],13:[function(require,module,exports){var _=require("lodash"),Graph=requ
 ire("graphlib").Graph;module.exports=buildLayerGraph;function buildLayerGraph(g,rank,relationship){var root=createRootNode(g),result=new Graph({compound:true}).setGraph({root:root}).setDefaultNodeLabel(function(v){return g.node(v)});_.each(g.nodes(),function(v){var node=g.node(v),parent=g.parent(v);if(node.rank===rank||node.minRank<=rank&&rank<=node.maxRank){result.setNode(v);result.setParent(v,parent||root);_.each(g[relationship](v),function(e){var u=e.v===v?e.w:e.v,edge=result.edge(u,v),weight=!_.isUndefined(edge)?edge.weight:0;result.setEdge(u,v,{weight:g.edge(e).weight+weight})});if(_.has(node,"minRank")){result.setNode(v,{borderLeft:node.borderLeft[rank],borderRight:node.borderRight[rank]})}}});return result}function createRootNode(g){var v;while(g.hasNode(v=_.uniqueId("_root")));return v}},{graphlib:29,lodash:48}],14:[function(require,module,exports){"use strict";var _=require("lodash");module.exports=crossCount;function crossCount(g,layering){var cc=0;for(var i=1;i<layering.l
 ength;++i){cc+=twoLayerCrossCount(g,layering[i-1],layering[i])}return cc}function twoLayerCrossCount(g,northLayer,southLayer){var southPos=_.zipObject(southLayer,_.map(southLayer,function(v,i){return i}));var southEntries=_.flatten(_.map(northLayer,function(v){return _.chain(g.outEdges(v)).map(function(e){return{pos:southPos[e.w],weight:g.edge(e).weight}}).sortBy("pos").value()}),true);var firstIndex=1;while(firstIndex<southLayer.length)firstIndex<<=1;var treeSize=2*firstIndex-1;firstIndex-=1;var tree=_.map(new Array(treeSize),function(){return 0});var cc=0;_.each(southEntries.forEach(function(entry){var index=entry.pos+firstIndex;tree[index]+=entry.weight;var weightSum=0;while(index>0){if(index%2){weightSum+=tree[index+1]}index=index-1>>1;tree[index]+=entry.weight}cc+=entry.weight*weightSum}));return cc}},{lodash:48}],15:[function(require,module,exports){"use strict";var _=require("lodash"),initOrder=require("./init-order"),crossCount=require("./cross-count"),sortSubgraph=require("
 ./sort-subgraph"),buildLayerGraph=require("./build-layer-graph"),addSubgraphConstraints=require("./add-subgraph-constraints"),Graph=require("graphlib").Graph,util=require("../util");module.exports=order;function order(g){var maxRank=util.maxRank(g),downLayerGraphs=buildLayerGraphs(g,_.range(1,maxRank+1),"inEdges"),upLayerGraphs=buildLayerGraphs(g,_.range(maxRank-1,-1,-1),"outEdges");var layering=initOrder(g);assignOrder(g,layering);var bestCC=Number.POSITIVE_INFINITY,best;for(var i=0,lastBest=0;lastBest<4;++i,++lastBest){sweepLayerGraphs(i%2?downLayerGraphs:upLayerGraphs,i%4>=2);layering=util.buildLayerMatrix(g);var cc=crossCount(g,layering);if(cc<bestCC){lastBest=0;best=_.cloneDeep(layering);bestCC=cc}}assignOrder(g,best)}function buildLayerGraphs(g,ranks,relationship){return _.map(ranks,function(rank){return buildLayerGraph(g,rank,relationship)})}function sweepLayerGraphs(layerGraphs,biasRight){var cg=new Graph;_.each(layerGraphs,function(lg){var root=lg.graph().root;var sorted=so
 rtSubgraph(lg,root,cg,biasRight);_.each(sorted.vs,function(v,i){lg.node(v).order=i});addSubgraphConstraints(lg,cg,sorted.vs)})}function assignOrder(g,layering){_.each(layering,function(layer){_.each(layer,function(v,i){g.node(v).order=i})})}},{"../util":27,"./add-subgraph-constraints":11,"./build-layer-graph":13,"./cross-count":14,"./init-order":16,"./sort-subgraph":18,graphlib:29,lodash:48}],16:[function(require,module,exports){"use strict";var _=require("lodash");module.exports=initOrder;function initOrder(g){var visited={},simpleNodes=_.filter(g.nodes(),function(v){return!g.children(v).length}),maxRank=_.max(_.map(simpleNodes,function(v){return g.node(v).rank})),layers=_.map(_.range(maxRank+1),function(){return[]});function dfs(v){if(_.has(visited,v))return;visited[v]=true;var node=g.node(v);layers[node.rank].push(v);_.each(g.successors(v),dfs)}var orderedVs=_.sortBy(simpleNodes,function(v){return g.node(v).rank});_.each(orderedVs,dfs);return layers}},{lodash:48}],17:[function(re
 quire,module,exports){"use strict";var _=require("lodash");module.exports=resolveConflicts;function resolveConflicts(entries,cg){var mappedEntries={};_.each(entries,function(entry,i){var tmp=mappedEntries[entry.v]={indegree:0,"in":[],out:[],vs:[entry.v],i:i};if(!_.isUndefined(entry.barycenter)){tmp.barycenter=entry.barycenter;tmp.weight=entry.weight}});_.each(cg.edges(),function(e){var entryV=mappedEntries[e.v],entryW=mappedEntries[e.w];if(!_.isUndefined(entryV)&&!_.isUndefined(entryW)){entryW.indegree++;entryV.out.push(mappedEntries[e.w])}});var sourceSet=_.filter(mappedEntries,function(entry){return!entry.indegree});return doResolveConflicts(sourceSet)}function doResolveConflicts(sourceSet){var entries=[];function handleIn(vEntry){return function(uEntry){if(uEntry.merged){return}if(_.isUndefined(uEntry.barycenter)||_.isUndefined(vEntry.barycenter)||uEntry.barycenter>=vEntry.barycenter){mergeEntries(vEntry,uEntry)}}}function handleOut(vEntry){return function(wEntry){wEntry.in.push(
 vEntry);if(--wEntry.indegree===0){sourceSet.push(wEntry)}}}while(sourceSet.length){var entry=sourceSet.pop();entries.push(entry);_.each(entry.in.reverse(),handleIn(entry));_.each(entry.out,handleOut(entry))}return _.chain(entries).filter(function(entry){return!entry.merged}).map(function(entry){return _.pick(entry,["vs","i","barycenter","weight"])}).value()}function mergeEntries(target,source){var sum=0,weight=0;if(target.weight){sum+=target.barycenter*target.weight;weight+=target.weight}if(source.weight){sum+=source.barycenter*source.weight;weight+=source.weight}target.vs=source.vs.concat(target.vs);target.barycenter=sum/weight;target.weight=weight;target.i=Math.min(source.i,target.i);source.merged=true}},{lodash:48}],18:[function(require,module,exports){var _=require("lodash"),barycenter=require("./barycenter"),resolveConflicts=require("./resolve-conflicts"),sort=require("./sort");module.exports=sortSubgraph;function sortSubgraph(g,v,cg,biasRight){var movable=g.children(v),node=g.
 node(v),bl=node?node.borderLeft:undefined,br=node?node.borderRight:undefined,subgraphs={};if(bl){movable=_.filter(movable,function(w){return w!==bl&&w!==br})}var barycenters=barycenter(g,movable);_.each(barycenters,function(entry){if(g.children(entry.v).length){var subgraphResult=sortSubgraph(g,entry.v,cg,biasRight);subgraphs[entry.v]=subgraphResult;if(_.has(subgraphResult,"barycenter")){mergeBarycenters(entry,subgraphResult)}}});var entries=resolveConflicts(barycenters,cg);expandSubgraphs(entries,subgraphs);var result=sort(entries,biasRight);if(bl){result.vs=_.flatten([bl,result.vs,br],true);if(g.predecessors(bl).length){var blPred=g.node(g.predecessors(bl)[0]),brPred=g.node(g.predecessors(br)[0]);if(!_.has(result,"barycenter")){result.barycenter=0;result.weight=0}result.barycenter=(result.barycenter*result.weight+blPred.order+brPred.order)/(result.weight+2);result.weight+=2}}return result}function expandSubgraphs(entries,subgraphs){_.each(entries,function(entry){entry.vs=_.flatten
 (entry.vs.map(function(v){if(subgraphs[v]){return subgraphs[v].vs}return v}),true)})}function mergeBarycenters(target,other){if(!_.isUndefined(target.barycenter)){target.barycenter=(target.barycenter*target.weight+other.barycenter*other.weight)/(target.weight+other.weight);target.weight+=other.weight}else{target.barycenter=other.barycenter;target.weight=other.weight}}},{"./barycenter":12,"./resolve-conflicts":17,"./sort":19,lodash:48}],19:[function(require,module,exports){var _=require("lodash"),util=require("../util");module.exports=sort;function sort(entries,biasRight){var parts=util.partition(entries,function(entry){return _.has(entry,"barycenter")});var sortable=parts.lhs,unsortable=_.sortBy(parts.rhs,function(entry){return-entry.i}),vs=[],sum=0,weight=0,vsIndex=0;sortable.sort(compareWithBias(!!biasRight));vsIndex=consumeUnsortable(vs,unsortable,vsIndex);_.each(sortable,function(entry){vsIndex+=entry.vs.length;vs.push(entry.vs);sum+=entry.barycenter*entry.weight;weight+=entry.w
 eight;vsIndex=consumeUnsortable(vs,unsortable,vsIndex)});var result={vs:_.flatten(vs,true)};if(weight){result.barycenter=sum/weight;result.weight=weight}return result}function consumeUnsortable(vs,unsortable,index){var last;while(unsortable.length&&(last=_.last(unsortable)).i<=index){unsortable.pop();vs.push(last.vs);index++}return index}function compareWithBias(bias){return function(entryV,entryW){if(entryV.barycenter<entryW.barycenter){return-1}else if(entryV.barycenter>entryW.barycenter){return 1}return!bias?entryV.i-entryW.i:entryW.i-entryV.i}}},{"../util":27,lodash:48}],20:[function(require,module,exports){var _=require("lodash");module.exports=parentDummyChains;function parentDummyChains(g){var postorderNums=postorder(g);_.each(g.graph().dummyChains,function(v){var node=g.node(v),edgeObj=node.edgeObj,pathData=findPath(g,postorderNums,edgeObj.v,edgeObj.w),path=pathData.path,lca=pathData.lca,pathIdx=0,pathV=path[pathIdx],ascending=true;while(v!==edgeObj.w){node=g.node(v);if(asce
 nding){while((pathV=path[pathIdx])!==lca&&g.node(pathV).maxRank<node.rank){pathIdx++}if(pathV===lca){ascending=false}}if(!ascending){while(pathIdx<path.length-1&&g.node(pathV=path[pathIdx+1]).minRank<=node.rank){pathIdx++}pathV=path[pathIdx]}g.setParent(v,pathV);v=g.successors(v)[0]}})}function findPath(g,postorderNums,v,w){var vPath=[],wPath=[],low=Math.min(postorderNums[v].low,postorderNums[w].low),lim=Math.max(postorderNums[v].lim,postorderNums[w].lim),parent,lca;parent=v;do{parent=g.parent(parent);vPath.push(parent)}while(parent&&(postorderNums[parent].low>low||lim>postorderNums[parent].lim));lca=parent;parent=w;while((parent=g.parent(parent))!==lca){wPath.push(parent)}return{path:vPath.concat(wPath.reverse()),lca:lca}}function postorder(g){var result={},lim=0;function dfs(v){var low=lim;_.each(g.children(v),dfs);result[v]={low:low,lim:lim++}}_.each(g.children(),dfs);return result}},{lodash:48}],21:[function(require,module,exports){"use strict";var _=require("lodash"),util=requi
 re("../util");module.exports={positionX:positionX,findType1Conflicts:findType1Conflicts,findType2Conflicts:findType2Conflicts,addConflict:addConflict,hasConflict:hasConflict,verticalAlignment:verticalAlignment,horizontalCompaction:horizontalCompaction,alignCoordinates:alignCoordinates,findSmallestWidthAlignment:findSmallestWidthAlignment,balance:balance};function findType1Conflicts(g,layering){var conflicts={};function visitLayer(prevLayer,layer){var k0=0,scanPos=0,prevLayerLength=prevLayer.length,lastNode=_.last(layer);_.each(layer,function(v,i){var w=findOtherInnerSegmentNode(g,v),k1=w?g.node(w).order:prevLayerLength;if(w||v===lastNode){_.each(layer.slice(scanPos,i+1),function(scanNode){_.each(g.predecessors(scanNode),function(u){var uLabel=g.node(u),uPos=uLabel.order;if((uPos<k0||k1<uPos)&&!(uLabel.dummy&&g.node(scanNode).dummy)){addConflict(conflicts,u,scanNode)}})});scanPos=i+1;k0=k1}});return layer}_.reduce(layering,visitLayer);return conflicts}function findType2Conflicts(g,la
 yering){var conflicts={};function scan(south,southPos,southEnd,prevNorthBorder,nextNorthBorder){var v;_.each(_.range(southPos,southEnd),function(i){v=south[i];if(g.node(v).dummy){_.each(g.predecessors(v),function(u){var uNode=g.node(u);if(uNode.dummy&&(uNode.order<prevNorthBorder||uNode.order>nextNorthBorder)){addConflict(conflicts,u,v)}})}})}function visitLayer(north,south){var prevNorthPos=-1,nextNorthPos,southPos=0;_.each(south,function(v,southLookahead){if(g.node(v).dummy==="border"){var predecessors=g.predecessors(v);if(predecessors.length){nextNorthPos=g.node(predecessors[0]).order;scan(south,southPos,southLookahead,prevNorthPos,nextNorthPos);southPos=southLookahead;prevNorthPos=nextNorthPos}}scan(south,southPos,south.length,nextNorthPos,north.length)});return south}_.reduce(layering,visitLayer);return conflicts}function findOtherInnerSegmentNode(g,v){if(g.node(v).dummy){return _.find(g.predecessors(v),function(u){return g.node(u).dummy})}}function addConflict(conflicts,v,w){i
 f(v>w){var tmp=v;v=w;w=tmp}var conflictsV=conflicts[v];if(!conflictsV){conflicts[v]=conflictsV={}}conflictsV[w]=true}function hasConflict(conflicts,v,w){if(v>w){var tmp=v;v=w;w=tmp}return _.has(conflicts[v],w)}function verticalAlignment(g,layering,conflicts,neighborFn){var root={},align={},pos={};_.each(layering,function(layer){_.each(layer,function(v,order){root[v]=v;align[v]=v;pos[v]=order})});_.each(layering,function(layer){var prevIdx=-1;_.each(layer,function(v){var ws=neighborFn(v);if(ws.length){ws=_.sortBy(ws,function(w){return pos[w]});var mp=(ws.length-1)/2;for(var i=Math.floor(mp),il=Math.ceil(mp);i<=il;++i){var w=ws[i];if(align[v]===v&&prevIdx<pos[w]&&!hasConflict(conflicts,v,w)){align[w]=v;align[v]=root[v]=root[w];prevIdx=pos[w]}}}})});return{root:root,align:align}}function horizontalCompaction(g,layering,root,align){var shift={},sink={},xs={},pred={},graphLabel=g.graph(),sepFn=sep(graphLabel.nodesep,graphLabel.edgesep);_.each(layering,function(layer){_.each(layer,functio
 n(v,order){sink[v]=v;shift[v]=Number.POSITIVE_INFINITY;pred[v]=layer[order-1]})});_.each(g.nodes(),function(v){if(root[v]===v){placeBlock(g,layering,sepFn,root,align,shift,sink,pred,xs,v)}});_.each(layering,function(layer){_.each(layer,function(v){xs[v]=xs[root[v]];if(v===root[v]&&shift[sink[root[v]]]<Number.POSITIVE_INFINITY){xs[v]+=shift[sink[root[v]]]}})});return xs}function placeBlock(g,layering,sepFn,root,align,shift,sink,pred,xs,v){if(_.has(xs,v))return;xs[v]=0;var w=v,u;do{if(pred[w]){u=root[pred[w]];placeBlock(g,layering,sepFn,root,align,shift,sink,pred,xs,u);if(sink[v]===v){sink[v]=sink[u]}var delta=sepFn(g,w,pred[w]);if(sink[v]!==sink[u]){shift[sink[u]]=Math.min(shift[sink[u]],xs[v]-xs[u]-delta)}else{xs[v]=Math.max(xs[v],xs[u]+delta)}}w=align[w]}while(w!==v)}function findSmallestWidthAlignment(g,xss){return _.min(xss,function(xs){var min=_.min(xs,function(x,v){return x-width(g,v)/2}),max=_.max(xs,function(x,v){return x+width(g,v)/2});return max-min})}function alignCoordina
 tes(xss,alignTo){var alignToMin=_.min(alignTo),alignToMax=_.max(alignTo);_.each(["u","d"],function(vert){_.each(["l","r"],function(horiz){var alignment=vert+horiz,xs=xss[alignment],delta;if(xs===alignTo)return;delta=horiz==="l"?alignToMin-_.min(xs):alignToMax-_.max(xs);if(delta){xss[alignment]=_.mapValues(xs,function(x){return x+delta})}})})}function balance(xss,align){return _.mapValues(xss.ul,function(ignore,v){if(align){return xss[align.toLowerCase()][v]}else{var xs=_.sortBy(_.pluck(xss,v));return(xs[1]+xs[2])/2}})}function positionX(g){var layering=util.buildLayerMatrix(g),conflicts=_.merge(findType1Conflicts(g,layering),findType2Conflicts(g,layering));
+var xss={},adjustedLayering;_.each(["u","d"],function(vert){adjustedLayering=vert==="u"?layering:_.values(layering).reverse();_.each(["l","r"],function(horiz){if(horiz==="r"){adjustedLayering=_.map(adjustedLayering,function(inner){return _.values(inner).reverse()})}var neighborFn=vert==="u"?g.predecessors.bind(g):g.successors.bind(g);var align=verticalAlignment(g,adjustedLayering,conflicts,neighborFn);var xs=horizontalCompaction(g,adjustedLayering,align.root,align.align);if(horiz==="r"){xs=_.mapValues(xs,function(x){return-x})}xss[vert+horiz]=xs})});var smallestWidth=findSmallestWidthAlignment(g,xss);alignCoordinates(xss,smallestWidth);return balance(xss,g.graph().align)}function sep(nodeSep,edgeSep){return function(g,v,u){var vLabel=g.node(v),uLabel=g.node(u),sums=uLabel.width+(uLabel.dummy?edgeSep:nodeSep)+(vLabel.dummy?edgeSep:nodeSep)+vLabel.width;return sums/2}}function width(g,v){return g.node(v).width}},{"../util":27,lodash:48}],22:[function(require,module,exports){"use stric
 t";var _=require("lodash"),util=require("../util"),positionX=require("./bk").positionX;module.exports=position;function position(g){g=util.asNonCompoundGraph(g);var rankDir=(g.graph().rankdir||"tb").toLowerCase();if(rankDir==="lr"||rankDir==="rl"){swapWidthHeight(g)}positionY(g);_.each(positionX(g),function(x,v){g.node(v).x=x});if(rankDir==="bt"||rankDir==="rl"){reverseY(g)}if(rankDir==="lr"||rankDir==="rl"){swapXY(g);swapWidthHeight(g)}translate(g)}function positionY(g){var layering=util.buildLayerMatrix(g),rankSep=g.graph().ranksep,prevY=0;_.each(layering,function(layer){var maxHeight=_.max(_.map(layer,function(v){return g.node(v).height}));_.each(layer,function(v){g.node(v).y=prevY+maxHeight/2});prevY+=maxHeight+rankSep})}function translate(g){var minX=Number.POSITIVE_INFINITY,maxX=0,minY=Number.POSITIVE_INFINITY,maxY=0,graphLabel=g.graph(),marginX=graphLabel.marginx||0,marginY=graphLabel.marginy||0;_.each(g.nodes(),function(v){var node=g.node(v),x=node.x,y=node.y,w=node.width,h=
 node.height;minX=Math.min(minX,x-w/2);maxX=Math.max(maxX,x+w/2);minY=Math.min(minY,y-h/2);maxY=Math.max(maxY,y+h/2)});minX-=marginX;minY-=marginY;_.each(g.nodes(),function(v){var node=g.node(v);node.x-=minX;node.y-=minY});graphLabel.width=maxX-minX+marginX;graphLabel.height=maxY-minY+marginY}function reverseY(g){_.each(g.nodes(),function(v){var node=g.node(v);node.y=-node.y})}function swapWidthHeight(g){_.each(g.nodes(),function(v){var node=g.node(v),width=node.width,height=node.height;node.width=height;node.height=width})}function swapXY(g){_.each(g.nodes(),function(v){var node=g.node(v),x=node.x,y=node.y;node.x=y;node.y=x})}},{"../util":27,"./bk":21,lodash:48}],23:[function(require,module,exports){"use strict";var _=require("lodash"),Graph=require("graphlib").Graph,slack=require("./util").slack;module.exports=feasibleTree;function feasibleTree(g){var t=new Graph({directed:false});var start=g.nodes()[0],size=g.nodeCount();t.setNode(start,{});var edge,delta;while(tightTree(t,g)<size
 ){edge=findMinSlackEdge(t,g);delta=t.hasNode(edge.v)?slack(g,edge):-slack(g,edge);shiftRanks(t,g,delta)}return t}function tightTree(t,g){function dfs(v){_.each(g.nodeEdges(v),function(e){var edgeV=e.v,w=v===edgeV?e.w:edgeV;if(!t.hasNode(w)&&!slack(g,e)){t.setNode(w,{});t.setEdge(v,w,{});dfs(w)}})}_.each(t.nodes(),dfs);return t.nodeCount()}function findMinSlackEdge(t,g){return _.min(g.edges(),function(e){if(t.hasNode(e.v)!==t.hasNode(e.w)){return slack(g,e)}})}function shiftRanks(t,g,delta){_.each(t.nodes(),function(v){g.node(v).rank+=delta})}},{"./util":26,graphlib:29,lodash:48}],24:[function(require,module,exports){"use strict";var rankUtil=require("./util"),longestPath=rankUtil.longestPath,feasibleTree=require("./feasible-tree"),networkSimplex=require("./network-simplex");module.exports=rank;function rank(g){switch(g.graph().ranker){case"network-simplex":networkSimplexRanker(g);break;case"tight-tree":tightTreeRanker(g);break;case"longest-path":longestPathRanker(g);break;default:ne
 tworkSimplexRanker(g)}}var longestPathRanker=longestPath;function tightTreeRanker(g){longestPath(g);feasibleTree(g)}function networkSimplexRanker(g){networkSimplex(g)}},{"./feasible-tree":23,"./network-simplex":25,"./util":26}],25:[function(require,module,exports){"use strict";var _=require("lodash"),feasibleTree=require("./feasible-tree"),slack=require("./util").slack,initRank=require("./util").longestPath,preorder=require("graphlib").alg.preorder,postorder=require("graphlib").alg.postorder,simplify=require("../util").simplify;module.exports=networkSimplex;networkSimplex.initLowLimValues=initLowLimValues;networkSimplex.initCutValues=initCutValues;networkSimplex.calcCutValue=calcCutValue;networkSimplex.leaveEdge=leaveEdge;networkSimplex.enterEdge=enterEdge;networkSimplex.exchangeEdges=exchangeEdges;function networkSimplex(g){g=simplify(g);initRank(g);var t=feasibleTree(g);initLowLimValues(t);initCutValues(t,g);var e,f;while(e=leaveEdge(t)){f=enterEdge(t,g,e);exchangeEdges(t,g,e,f)}}
 function initCutValues(t,g){var vs=postorder(t,t.nodes());vs=vs.slice(0,vs.length-1);_.each(vs,function(v){assignCutValue(t,g,v)})}function assignCutValue(t,g,child){var childLab=t.node(child),parent=childLab.parent;t.edge(child,parent).cutvalue=calcCutValue(t,g,child)}function calcCutValue(t,g,child){var childLab=t.node(child),parent=childLab.parent,childIsTail=true,graphEdge=g.edge(child,parent),cutValue=0;if(!graphEdge){childIsTail=false;graphEdge=g.edge(parent,child)}cutValue=graphEdge.weight;_.each(g.nodeEdges(child),function(e){var isOutEdge=e.v===child,other=isOutEdge?e.w:e.v;if(other!==parent){var pointsToHead=isOutEdge===childIsTail,otherWeight=g.edge(e).weight;cutValue+=pointsToHead?otherWeight:-otherWeight;if(isTreeEdge(t,child,other)){var otherCutValue=t.edge(child,other).cutvalue;cutValue+=pointsToHead?-otherCutValue:otherCutValue}}});return cutValue}function initLowLimValues(tree,root){if(arguments.length<2){root=tree.nodes()[0]}dfsAssignLowLim(tree,{},1,root)}function
  dfsAssignLowLim(tree,visited,nextLim,v,parent){var low=nextLim,label=tree.node(v);visited[v]=true;_.each(tree.neighbors(v),function(w){if(!_.has(visited,w)){nextLim=dfsAssignLowLim(tree,visited,nextLim,w,v)}});label.low=low;label.lim=nextLim++;if(parent){label.parent=parent}else{delete label.parent}return nextLim}function leaveEdge(tree){return _.find(tree.edges(),function(e){return tree.edge(e).cutvalue<0})}function enterEdge(t,g,edge){var v=edge.v,w=edge.w;if(!g.hasEdge(v,w)){v=edge.w;w=edge.v}var vLabel=t.node(v),wLabel=t.node(w),tailLabel=vLabel,flip=false;if(vLabel.lim>wLabel.lim){tailLabel=wLabel;flip=true}var candidates=_.filter(g.edges(),function(edge){return flip===isDescendant(t,t.node(edge.v),tailLabel)&&flip!==isDescendant(t,t.node(edge.w),tailLabel)});return _.min(candidates,function(edge){return slack(g,edge)})}function exchangeEdges(t,g,e,f){var v=e.v,w=e.w;t.removeEdge(v,w);t.setEdge(f.v,f.w,{});initLowLimValues(t);initCutValues(t,g);updateRanks(t,g)}function update
 Ranks(t,g){var root=_.find(t.nodes(),function(v){return!g.node(v).parent}),vs=preorder(t,root);vs=vs.slice(1);_.each(vs,function(v){var parent=t.node(v).parent,edge=g.edge(v,parent),flipped=false;if(!edge){edge=g.edge(parent,v);flipped=true}g.node(v).rank=g.node(parent).rank+(flipped?edge.minlen:-edge.minlen)})}function isTreeEdge(tree,u,v){return tree.hasEdge(u,v)}function isDescendant(tree,vLabel,rootLabel){return rootLabel.low<=vLabel.lim&&vLabel.lim<=rootLabel.lim}},{"../util":27,"./feasible-tree":23,"./util":26,graphlib:29,lodash:48}],26:[function(require,module,exports){"use strict";var _=require("lodash");module.exports={longestPath:longestPath,slack:slack};function longestPath(g){var visited={};function dfs(v){var label=g.node(v);if(_.has(visited,v)){return label.rank}visited[v]=true;var rank=_.min(_.map(g.outEdges(v),function(e){return dfs(e.w)-g.edge(e).minlen}));if(rank===Number.POSITIVE_INFINITY){rank=0}return label.rank=rank}_.each(g.sources(),dfs)}function slack(g,e){r
 eturn g.node(e.w).rank-g.node(e.v).rank-g.edge(e).minlen}},{lodash:48}],27:[function(require,module,exports){"use strict";var _=require("lodash"),Graph=require("graphlib").Graph;module.exports={addDummyNode:addDummyNode,simplify:simplify,asNonCompoundGraph:asNonCompoundGraph,successorWeights:successorWeights,predecessorWeights:predecessorWeights,intersectRect:intersectRect,buildLayerMatrix:buildLayerMatrix,normalizeRanks:normalizeRanks,removeEmptyRanks:removeEmptyRanks,addBorderNode:addBorderNode,maxRank:maxRank,partition:partition,time:time,notime:notime};function addDummyNode(g,type,attrs,name){var v;do{v=_.uniqueId(name)}while(g.hasNode(v));attrs.dummy=type;g.setNode(v,attrs);return v}function simplify(g){var simplified=(new Graph).setGraph(g.graph());_.each(g.nodes(),function(v){simplified.setNode(v,g.node(v))});_.each(g.edges(),function(e){var simpleLabel=simplified.edge(e.v,e.w)||{weight:0,minlen:1},label=g.edge(e);simplified.setEdge(e.v,e.w,{weight:simpleLabel.weight+label.we
 ight,minlen:Math.max(simpleLabel.minlen,label.minlen)})});return simplified}function asNonCompoundGraph(g){var simplified=new Graph({multigraph:g.isMultigraph()}).setGraph(g.graph());_.each(g.nodes(),function(v){if(!g.children(v).length){simplified.setNode(v,g.node(v))}});_.each(g.edges(),function(e){simplified.setEdge(e,g.edge(e))});return simplified}function successorWeights(g){var weightMap=_.map(g.nodes(),function(v){var sucs={};_.each(g.outEdges(v),function(e){sucs[e.w]=(sucs[e.w]||0)+g.edge(e).weight});return sucs});return _.zipObject(g.nodes(),weightMap)}function predecessorWeights(g){var weightMap=_.map(g.nodes(),function(v){var preds={};_.each(g.inEdges(v),function(e){preds[e.v]=(preds[e.v]||0)+g.edge(e).weight});return preds});return _.zipObject(g.nodes(),weightMap)}function intersectRect(rect,point){var x=rect.x;var y=rect.y;var dx=point.x-x;var dy=point.y-y;var w=rect.width/2;var h=rect.height/2;if(!dx&&!dy){throw new Error("Not possible to find intersection inside of th
 e rectangle")}var sx,sy;if(Math.abs(dy)*w>Math.abs(dx)*h){if(dy<0){h=-h}sx=h*dx/dy;sy=h}else{if(dx<0){w=-w}sx=w;sy=w*dy/dx}return{x:x+sx,y:y+sy}}function buildLayerMatrix(g){var layering=_.map(_.range(maxRank(g)+1),function(){return[]});_.each(g.nodes(),function(v){var node=g.node(v),rank=node.rank;if(!_.isUndefined(rank)){layering[rank][node.order]=v}});return layering}function normalizeRanks(g){var min=_.min(_.map(g.nodes(),function(v){return g.node(v).rank}));_.each(g.nodes(),function(v){var node=g.node(v);if(_.has(node,"rank")){node.rank-=min}})}function removeEmptyRanks(g){var offset=_.min(_.map(g.nodes(),function(v){return g.node(v).rank}));var layers=[];_.each(g.nodes(),function(v){var rank=g.node(v).rank-offset;if(!_.has(layers,rank)){layers[rank]=[]}layers[rank].push(v)});var delta=0,nodeRankFactor=g.graph().nodeRankFactor;_.each(layers,function(vs,i){if(_.isUndefined(vs)&&i%nodeRankFactor!==0){--delta}else if(delta){_.each(vs,function(v){g.node(v).rank+=delta})}})}function
  addBorderNode(g,prefix,rank,order){var node={width:0,height:0};if(arguments.length>=4){node.rank=rank;node.order=order}return addDummyNode(g,"border",node,prefix)}function maxRank(g){return _.max(_.map(g.nodes(),function(v){var rank=g.node(v).rank;if(!_.isUndefined(rank)){return rank}}))}function partition(collection,fn){var result={lhs:[],rhs:[]};_.each(collection,function(value){if(fn(value)){result.lhs.push(value)}else{result.rhs.push(value)}});return result}function time(name,fn){var start=_.now();try{return fn()}finally{console.log(name+" time: "+(_.now()-start)+"ms")}}function notime(name,fn){return fn()}},{graphlib:29,lodash:48}],28:[function(require,module,exports){module.exports="0.5.1"},{}],29:[function(require,module,exports){var _=require("lodash");module.exports=_.clone(require("./lib"));module.exports.json=require("./lib/json");module.exports.alg=require("./lib/alg")},{"./lib":45,"./lib/alg":36,"./lib/json":46,lodash:48}],30:[function(require,module,exports){var _=req
 uire("lodash");module.exports=components;function components(g){var visited={},cmpts=[],cmpt;function dfs(v){if(_.has(visited,v))return;visited[v]=true;cmpt.push(v);_.each(g.successors(v),dfs);_.each(g.predecessors(v),dfs)}_.each(g.nodes(),function(v){cmpt=[];dfs(v);if(cmpt.length){cmpts.push(cmpt)}});return cmpts}},{lodash:48}],31:[function(require,module,exports){var _=require("lodash");module.exports=dfs;function dfs(g,vs,order){if(!_.isArray(vs)){vs=[vs]}var acc=[],visited={};_.each(vs,function(v){if(!g.hasNode(v)){throw new Error("Graph does not have node: "+v)}doDfs(g,v,order==="post",visited,acc)});return acc}function doDfs(g,v,postorder,visited,acc){if(!_.has(visited,v)){visited[v]=true;if(!postorder){acc.push(v)}_.each(g.neighbors(v),function(w){doDfs(g,w,postorder,visited,acc)});if(postorder){acc.push(v)}}}},{lodash:48}],32:[function(require,module,exports){var dijkstra=require("./dijkstra"),_=require("lodash");module.exports=dijkstraAll;function dijkstraAll(g,weightFunc,e
 dgeFunc){return _.transform(g.nodes(),function(acc,v){acc[v]=dijkstra(g,v,weightFunc,edgeFunc)},{})}},{"./dijkstra":33,lodash:48}],33:[function(require,module,exports){var _=require("lodash"),PriorityQueue=require("../data/priority-queue");module.exports=dijkstra;var DEFAULT_WEIGHT_FUNC=_.constant(1);function dijkstra(g,source,weightFn,edgeFn){return runDijkstra(g,String(source),weightFn||DEFAULT_WEIGHT_FUNC,edgeFn||function(v){return g.outEdges(v)})}function runDijkstra(g,source,weightFn,edgeFn){var results={},pq=new PriorityQueue,v,vEntry;var updateNeighbors=function(edge){var w=edge.v!==v?edge.v:edge.w,wEntry=results[w],weight=weightFn(edge),distance=vEntry.distance+weight;if(weight<0){throw new Error("dijkstra does not allow negative edge weights. "+"Bad edge: "+edge+" Weight: "+weight)}if(distance<wEntry.distance){wEntry.distance=distance;wEntry.predecessor=v;pq.decrease(w,distance)}};g.nodes().forEach(function(v){var distance=v===source?0:Number.POSITIVE_INFINITY;results[v]={d
 istance:distance};pq.add(v,distance)});while(pq.size()>0){v=pq.removeMin();vEntry=results[v];if(vEntry.distance===Number.POSITIVE_INFINITY){break}edgeFn(v).forEach(updateNeighbors)}return results}},{"../data/priority-queue":43,lodash:48}],34:[function(require,module,exports){var _=require("lodash"),tarjan=require("./tarjan");module.exports=findCycles;function findCycles(g){return _.filter(tarjan(g),function(cmpt){return cmpt.length>1})}},{"./tarjan":41,lodash:48}],35:[function(require,module,exports){var _=require("lodash");module.exports=floydWarshall;var DEFAULT_WEIGHT_FUNC=_.constant(1);function floydWarshall(g,weightFn,edgeFn){return runFloydWarshall(g,weightFn||DEFAULT_WEIGHT_FUNC,edgeFn||function(v){return g.outEdges(v)})}function runFloydWarshall(g,weightFn,edgeFn){var results={},nodes=g.nodes();nodes.forEach(function(v){results[v]={};results[v][v]={distance:0};nodes.forEach(function(w){if(v!==w){results[v][w]={distance:Number.POSITIVE_INFINITY}}});edgeFn(v).forEach(function(
 edge){var w=edge.v===v?edge.w:edge.v,d=weightFn(edge);results[v][w]={distance:d,predecessor:v}})});nodes.forEach(function(k){var rowK=results[k];nodes.forEach(function(i){var rowI=results[i];nodes.forEach(function(j){var ik=rowI[k];var kj=rowK[j];var ij=rowI[j];var altDistance=ik.distance+kj.distance;if(altDistance<ij.distance){ij.distance=altDistance;ij.predecessor=kj.predecessor}})})});return results}},{lodash:48}],36:[function(require,module,exports){module.exports={components:require("./components"),dijkstra:require("./dijkstra"),dijkstraAll:require("./dijkstra-all"),findCycles:require("./find-cycles"),floydWarshall:require("./floyd-warshall"),isAcyclic:require("./is-acyclic"),postorder:require("./postorder"),preorder:require("./preorder"),prim:require("./prim"),tarjan:require("./tarjan"),topsort:require("./topsort")}},{"./components":30,"./dijkstra":33,"./dijkstra-all":32,"./find-cycles":34,"./floyd-warshall":35,"./is-acyclic":37,"./postorder":38,"./preorder":39,"./prim":40,"./
 tarjan":41,"./topsort":42}],37:[function(require,module,exports){var topsort=require("./topsort");module.exports=isAcyclic;function isAcyclic(g){try{topsort(g)}catch(e){if(e instanceof topsort.CycleException){return false}throw e}return true}},{"./topsort":42}],38:[function(require,module,exports){var dfs=require("./dfs");module.exports=postorder;function postorder(g,vs){return dfs(g,vs,"post")}},{"./dfs":31}],39:[function(require,module,exports){var dfs=require("./dfs");module.exports=preorder;function preorder(g,vs){return dfs(g,vs,"pre")}},{"./dfs":31}],40:[function(require,module,exports){var _=require("lodash"),Graph=require("../graph"),PriorityQueue=require("../data/priority-queue");module.exports=prim;function prim(g,weightFunc){var result=new Graph,parents={},pq=new PriorityQueue,v;function updateNeighbors(edge){var w=edge.v===v?edge.w:edge.v,pri=pq.priority(w);if(pri!==undefined){var edgeWeight=weightFunc(edge);if(edgeWeight<pri){parents[w]=v;pq.decrease(w,edgeWeight)}}}if(
 g.nodeCount()===0){return result}_.each(g.nodes(),function(v){pq.add(v,Number.POSITIVE_INFINITY);result.setNode(v)});pq.decrease(g.nodes()[0],0);var init=false;while(pq.size()>0){v=pq.removeMin();if(_.has(parents,v)){result.setEdge(v,parents[v])}else if(init){throw new Error("Input graph is not connected: "+g)}else{init=true}g.nodeEdges(v).forEach(updateNeighbors)}return result}},{"../data/priority-queue":43,"../graph":44,lodash:48}],41:[function(require,module,exports){var _=require("lodash");module.exports=tarjan;function tarjan(g){var index=0,stack=[],visited={},results=[];function dfs(v){var entry=visited[v]={onStack:true,lowlink:index,index:index++};stack.push(v);g.successors(v).forEach(function(w){if(!_.has(visited,w)){dfs(w);entry.lowlink=Math.min(entry.lowlink,visited[w].lowlink)}else if(visited[w].onStack){entry.lowlink=Math.min(entry.lowlink,visited[w].index)}});if(entry.lowlink===entry.index){var cmpt=[],w;do{w=stack.pop();visited[w].onStack=false;cmpt.push(w)}while(v!==w
 );results.push(cmpt)}}g.nodes().forEach(function(v){if(!_.has(visited,v)){dfs(v)}});return results}},{lodash:48}],42:[function(require,module,exports){var _=require("lodash");module.exports=topsort;topsort.CycleException=CycleException;function topsort(g){var visited={},stack={},results=[];function visit(node){if(_.has(stack,node)){throw new CycleException}if(!_.has(visited,node)){stack[node]=true;visited[node]=true;_.each(g.predecessors(node),visit);delete stack[node];results.push(node)}}_.each(g.sinks(),visit);if(_.size(visited)!==g.nodeCount()){throw new CycleException}return results}function CycleException(){}},{lodash:48}],43:[function(require,module,exports){var _=require("lodash");module.exports=PriorityQueue;function PriorityQueue(){this._arr=[];this._keyIndices={}}PriorityQueue.prototype.size=function(){return this._arr.length};PriorityQueue.prototype.keys=function(){return this._arr.map(function(x){return x.key})};PriorityQueue.prototype.has=function(key){return _.has(this
 ._keyIndices,key)};PriorityQueue.prototype.priority=function(key){var index=this._keyIndices[key];if(index!==undefined){return this._arr[index].priority}};PriorityQueue.prototype.min=function(){if(this.size()===0){throw new Error("Queue underflow")}return this._arr[0].key};PriorityQueue.prototype.add=function(key,priority){var keyIndices=this._keyIndices;key=String(key);if(!_.has(keyIndices,key)){var arr=this._arr;var index=arr.length;keyIndices[key]=index;arr.push({key:key,priority:priority});this._decrease(index);return true}return false};PriorityQueue.prototype.removeMin=function(){this._swap(0,this._arr.length-1);var min=this._arr.pop();delete this._keyIndices[min.key];this._heapify(0);return min.key};PriorityQueue.prototype.decrease=function(key,priority){var index=this._keyIndices[key];if(priority>this._arr[index].priority){throw new Error("New priority is greater than current priority. "+"Key: "+key+" Old: "+this._arr[index].priority+" New: "+priority)}this._arr[index].priori
 ty=priority;this._decrease(index)};PriorityQueue.prototype._heapify=function(i){var arr=this._arr;var l=2*i,r=l+1,largest=i;if(l<arr.length){largest=arr[l].priority<arr[largest].priority?l:largest;if(r<arr.length){largest=arr[r].priority<arr[largest].priority?r:largest}if(largest!==i){this._swap(i,largest);this._heapify(largest)}}};PriorityQueue.prototype._decrease=function(index){var arr=this._arr;var priority=arr[index].priority;var parent;while(index!==0){parent=index>>1;if(arr[parent].priority<priority){break}this._swap(index,parent);index=parent}};PriorityQueue.prototype._swap=function(i,j){var arr=this._arr;var keyIndices=this._keyIndices;var origArrI=arr[i];var origArrJ=arr[j];arr[i]=origArrJ;arr[j]=origArrI;keyIndices[origArrJ.key]=i;keyIndices[origArrI.key]=j}},{lodash:48}],44:[function(require,module,exports){"use strict";var _=require("lodash");module.exports=Graph;var DEFAULT_EDGE_NAME="\x00",GRAPH_NODE="\x00",EDGE_KEY_DELIM="";function Graph(opts){this._isDirected=_.ha
 s(opts,"directed")?opts.directed:true;this._isMultigraph=_.has(opts,"multigraph")?opts.multigraph:false;this._isCompound=_.has(opts,"compound")?opts.compound:false;this._label=undefined;this._defaultNodeLabelFn=_.constant(undefined);this._defaultEdgeLabelFn=_.constant(undefined);this._nodes={};if(this._isCompound){this._parent={};this._children={};this._children[GRAPH_NODE]={}}this._in={};this._preds={};this._out={};this._sucs={};this._edgeObjs={};this._edgeLabels={}}Graph.prototype._nodeCount=0;Graph.prototype._edgeCount=0;Graph.prototype.isDirected=function(){return this._isDirected};Graph.prototype.isMultigraph=function(){return this._isMultigraph};Graph.prototype.isCompound=function(){return this._isCompound};Graph.prototype.setGraph=function(label){this._label=label;return this};Graph.prototype.graph=function(){return this._label};Graph.prototype.setDefaultNodeLabel=function(newDefault){if(!_.isFunction(newDefault)){newDefault=_.constant(newDefault)}this._defaultNodeLabelFn=new
 Default;return this};Graph.prototype.nodeCount=function(){return this._nodeCount};Graph.prototype.nodes=function(){return _.keys(this._nodes)};Graph.prototype.sources=function(){return _.filter(this.nodes(),function(v){return _.isEmpty(this._in[v])},this)};Graph.prototype.sinks=function(){return _.filter(this.nodes(),function(v){return _.isEmpty(this._out[v])},this)};Graph.prototype.setNodes=function(vs,value){var args=arguments;_.each(vs,function(v){if(args.length>1){this.setNode(v,value)}else{this.setNode(v)}},this);return this};Graph.prototype.setNode=function(v,value){if(_.has(this._nodes,v)){if(arguments.length>1){this._nodes[v]=value}return this}this._nodes[v]=arguments.length>1?value:this._defaultNodeLabelFn(v);if(this._isCompound){this._parent[v]=GRAPH_NODE;this._children[v]={};this._children[GRAPH_NODE][v]=true}this._in[v]={};this._preds[v]={};this._out[v]={};this._sucs[v]={};++this._nodeCount;return this};Graph.prototype.node=function(v){return this._nodes[v]};Graph.protot
 ype.hasNode=function(v){return _.has(this._nodes,v)};Graph.prototype.removeNode=function(v){var self=this;if(_.has(this._nodes,v)){var removeEdge=function(e){self.removeEdge(self._edgeObjs[e])};delete this._nodes[v];if(this._isCompound){this._removeFromParentsChildList(v);delete this._parent[v];_.each(this.children(v),function(child){this.setParent(child)},this);delete this._children[v]}_.each(_.keys(this._in[v]),removeEdge);delete this._in[v];delete this._preds[v];_.each(_.keys(this._out[v]),removeEdge);delete this._out[v];delete this._sucs[v];--this._nodeCount}return this};Graph.prototype.setParent=function(v,parent){if(!this._isCompound){throw new Error("Cannot set parent in a non-compound graph")}if(_.isUndefined(parent)){parent=GRAPH_NODE}else{for(var ancestor=parent;!_.isUndefined(ancestor);ancestor=this.parent(ancestor)){if(ancestor===v){throw new Error("Setting "+parent+" as parent of "+v+" would create create a cycle")}}this.setNode(parent)}this.setNode(v);this._removeFromP
 arentsChildList(v);this._parent[v]=parent;this._children[parent][v]=true;return this};Graph.prototype._removeFromParentsChildList=function(v){delete this._children[this._parent[v]][v]};Graph.prototype.parent=function(v){if(this._isCompound){var parent=this._parent[v];if(parent!==GRAPH_NODE){return parent}}};Graph.prototype.children=function(v){if(_.isUndefined(v)){v=GRAPH_NODE}if(this._isCompound){var children=this._children[v];if(children){return _.keys(children)}}else if(v===GRAPH_NODE){return this.nodes()}else if(this.hasNode(v)){return[]}};Graph.prototype.predecessors=function(v){var predsV=this._preds[v];if(predsV){return _.keys(predsV)}};Graph.prototype.successors=function(v){var sucsV=this._sucs[v];if(sucsV){return _.keys(sucsV)}};Graph.prototype.neighbors=function(v){var preds=this.predecessors(v);if(preds){return _.union(preds,this.successors(v))}};Graph.prototype.setDefaultEdgeLabel=function(newDefault){if(!_.isFunction(newDefault)){newDefault=_.constant(newDefault)}this._
 defaultEdgeLabelFn=newDefault;return this};Graph.prototype.edgeCount=function(){return this._edgeCount};Graph.prototype.edges=function(){return _.values(this._edgeObjs)};Graph.prototype.setPath=function(vs,value){var self=this,args=arguments;_.reduce(vs,function(v,w){if(args.length>1){self.setEdge(v,w,value)}else{self.setEdge(v,w)}return w});return this};Graph.prototype.setEdge=function(v,w,value,name){var valueSpecified=arguments.length>2;if(_.isPlainObject(arguments[0])){v=arguments[0].v;w=arguments[0].w;name=arguments[0].name;if(arguments.length===2){value=arguments[1];valueSpecified=true}}var e=edgeArgsToId(this._isDirected,v,w,name);if(_.has(this._edgeLabels,e)){if(valueSpecified){this._edgeLabels[e]=value}return this}if(!_.isUndefined(name)&&!this._isMultigraph){throw new Error("Cannot set a named edge when isMultigraph = false")}this.setNode(v);this.setNode(w);this._edgeLabels[e]=valueSpecified?value:this._defaultEdgeLabelFn(v,w,name);var edgeObj=edgeArgsToObj(this._isDirecte
 d,v,w,name);v=edgeObj.v;w=edgeObj.w;Object.freeze(edgeObj);this._edgeObjs[e]=edgeObj;incrementOrInitEntry(this._preds[w],v);incrementOrInitEntry(this._sucs[v],w);this._in[w][e]=edgeObj;this._out[v][e]=edgeObj;this._edgeCount++;return this};Graph.prototype.edge=function(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return this._edgeLabels[e]};Graph.prototype.hasEdge=function(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return _.has(this._edgeLabels,e)};Graph.prototype.removeEdge=function(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name),edge=this._edgeObjs[e];if(edge){v=edge.v;w=edge.w;delete this._edgeLabels[e];delete this._edgeObjs[e];decrementOrRemoveEntry(this._preds[w],v);decrementOrRemoveEntry(this._sucs[v],w);delete this._in[w][e];delete this._out[v][e];this._ed
 geCount--}return this};Graph.prototype.inEdges=function(v,u){var inV=this._in[v];if(inV){var edges=_.values(inV);if(!u){return edges}return _.filter(edges,function(edge){return edge.v===u})}};Graph.prototype.outEdges=function(v,w){var outV=this._out[v];if(outV){var edges=_.values(outV);if(!w){return edges}return _.filter(edges,function(edge){return edge.w===w})}};Graph.prototype.nodeEdges=function(v,w){var inEdges=this.inEdges(v,w);if(inEdges){return inEdges.concat(this.outEdges(v,w))}};function incrementOrInitEntry(map,k){if(_.has(map,k)){map[k]++}else{map[k]=1}}function decrementOrRemoveEntry(map,k){if(!--map[k]){delete map[k]}}function edgeArgsToId(isDirected,v,w,name){if(!isDirected&&v>w){var tmp=v;v=w;w=tmp}return v+EDGE_KEY_DELIM+w+EDGE_KEY_DELIM+(_.isUndefined(name)?DEFAULT_EDGE_NAME:name)}function edgeArgsToObj(isDirected,v,w,name){if(!isDirected&&v>w){var tmp=v;v=w;w=tmp}var edgeObj={v:v,w:w};if(name){edgeObj.name=name}return edgeObj}function edgeObjToId(isDirected,edgeObj)
 {return edgeArgsToId(isDirected,edgeObj.v,edgeObj.w,edgeObj.name)}},{lodash:48}],45:[function(require,module,exports){module.exports={Graph:require("./graph"),version:require("./version")}},{"./graph":44,"./version":47}],46:[function(require,module,exports){var _=require("lodash"),Graph=require("./graph");module.exports={write:write,read:read};function write(g){var json={options:{directed:g.isDirected(),multigraph:g.isMultigraph(),compound:g.isCompound()},nodes:writeNodes(g),edges:writeEdges(g)};if(!_.isUndefined(g.graph())){json.value=_.clone(g.graph())}return json}function writeNodes(g){return _.map(g.nodes(),function(v){var nodeValue=g.node(v),parent=g.parent(v),node={v:v};if(!_.isUndefined(nodeValue)){node.value=nodeValue}if(!_.isUndefined(parent)){node.parent=parent}return node})}function writeEdges(g){return _.map(g.edges(),function(e){var edgeValue=g.edge(e),edge={v:e.v,w:e.w};if(!_.isUndefined(e.name)){edge.name=e.name}if(!_.isUndefined(edgeValue)){edge.value=edgeValue}retur
 n edge})}function read(json){var g=new Graph(json.options).setGraph(json.value);_.each(json.nodes,function(entry){g.setNode(entry.v,entry.value);if(entry.parent){g.setParent(entry.v,entry.parent)}});_.each(json.edges,function(entry){g.setEdge({v:entry.v,w:entry.w,name:entry.name},entry.value)});return g}},{"./graph":44,lodash:48}],47:[function(require,module,exports){module.exports="0.8.0"},{}],48:[function(require,module,exports){(function(global){(function(){var undefined;var arrayPool=[],objectPool=[];var idCounter=0;var keyPrefix=+new Date+"";var largeArraySize=75;var maxPoolSize=40;var whitespace="   \f \ufeff"+"\n\r\u2028\u2029"+"\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000";var reEmptyStringLeading=/\b__p \+= '';/g,reEmptyStringMiddle=/\b(__p \+=) '' \+/g,reEmptyStringTrailing=/(__e\(.*?\)|\b__t\)) \+\n'';/g;var reEsTemplate=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;var reFlags=/\w*$/;var reFuncName=/^\s*function[ \n\r\t]+\w/;var reInterpolate=/<%=([\s\S]+?)%>/g;var reLeadingSpaces
 AndZeros=RegExp("^["+whitespace+"]*0+(?=.$)");var reNoMatch=/($^)/;var reThis=/\bthis\b/;var reUnescapedString=/['\n\r\t\u2028\u2029\\]/g;var contextProps=["Array","Boolean","Date","Function","Math","Number","Object","RegExp","String","_","attachEvent","clearTimeout","isFinite","isNaN","parseInt","setTimeout"];var templateCounter=0;var argsClass="[object Arguments]",arrayClass="[object Array]",boolClass="[object Boolean]",dateClass="[object Date]",funcClass="[object Function]",numberClass="[object Number]",objectClass="[object Object]",regexpClass="[object RegExp]",stringClass="[object String]";var cloneableClasses={};cloneableClasses[funcClass]=false;cloneableClasses[argsClass]=cloneableClasses[arrayClass]=cloneableClasses[boolClass]=cloneableClasses[dateClass]=cloneableClasses[numberClass]=cloneableClasses[objectClass]=cloneableClasses[regexpClass]=cloneableClasses[stringClass]=true;var debounceOptions={leading:false,maxWait:0,trailing:false};var descriptor={configurable:false,enu
 merable:false,value:null,writable:false};var objectTypes={"boolean":false,"function":true,object:true,number:false,string:false,undefined:false};var stringEscapes={"\\":"\\","'":"'","\n":"n","\r":"r","  ":"t","\u2028":"u2028","\u2029":"u2029"};var root=objectTypes[typeof window]&&window||this;var freeExports=objectTypes[typeof exports]&&exports&&!exports.nodeType&&exports;var freeModule=objectTypes[typeof module]&&module&&!module.nodeType&&module;var moduleExports=freeModule&&freeModule.exports===freeExports&&freeExports;var freeGlobal=objectTypes[typeof global]&&global;if(freeGlobal&&(freeGlobal.global===freeGlobal||freeGlobal.window===freeGlobal)){root=freeGlobal}function baseIndexOf(array,value,fromIndex){var index=(fromIndex||0)-1,length=array?array.length:0;while(++index<length){if(array[index]===value){return index}}return-1}function cacheIndexOf(cache,value){var type=typeof value;cache=cache.cache;if(type=="boolean"||value==null){return cache[value]?0:-1}if(type!="number"&&ty
 pe!="string"){type="object"}var key=type=="number"?value:keyPrefix+value;cache=(cache=cache[type])&&cache[key];return type=="object"?cache&&baseIndexOf(cache,value)>-1?0:-1:cache?0:-1
+}function cachePush(value){var cache=this.cache,type=typeof value;if(type=="boolean"||value==null){cache[value]=true}else{if(type!="number"&&type!="string"){type="object"}var key=type=="number"?value:keyPrefix+value,typeCache=cache[type]||(cache[type]={});if(type=="object"){(typeCache[key]||(typeCache[key]=[])).push(value)}else{typeCache[key]=true}}}function charAtCallback(value){return value.charCodeAt(0)}function compareAscending(a,b){var ac=a.criteria,bc=b.criteria,index=-1,length=ac.length;while(++index<length){var value=ac[index],other=bc[index];if(value!==other){if(value>other||typeof value=="undefined"){return 1}if(value<other||typeof other=="undefined"){return-1}}}return a.index-b.index}function createCache(array){var index=-1,length=array.length,first=array[0],mid=array[length/2|0],last=array[length-1];if(first&&typeof first=="object"&&mid&&typeof mid=="object"&&last&&typeof last=="object"){return false}var cache=getObject();cache["false"]=cache["null"]=cache["true"]=cache[
 "undefined"]=false;var result=getObject();result.array=array;result.cache=cache;result.push=cachePush;while(++index<length){result.push(array[index])}return result}function escapeStringChar(match){return"\\"+stringEscapes[match]}function getArray(){return arrayPool.pop()||[]}function getObject(){return objectPool.pop()||{array:null,cache:null,criteria:null,"false":false,index:0,"null":false,number:null,object:null,push:null,string:null,"true":false,undefined:false,value:null}}function releaseArray(array){array.length=0;if(arrayPool.length<maxPoolSize){arrayPool.push(array)}}function releaseObject(object){var cache=object.cache;if(cache){releaseObject(cache)}object.array=object.cache=object.criteria=object.object=object.number=object.string=object.value=null;if(objectPool.length<maxPoolSize){objectPool.push(object)}}function slice(array,start,end){start||(start=0);if(typeof end=="undefined"){end=array?array.length:0}var index=-1,length=end-start||0,result=Array(length<0?0:length);whi
 le(++index<length){result[index]=array[start+index]}return result}function runInContext(context){context=context?_.defaults(root.Object(),context,_.pick(root,contextProps)):root;var Array=context.Array,Boolean=context.Boolean,Date=context.Date,Function=context.Function,Math=context.Math,Number=context.Number,Object=context.Object,RegExp=context.RegExp,String=context.String,TypeError=context.TypeError;var arrayRef=[];var objectProto=Object.prototype;var oldDash=context._;var toString=objectProto.toString;var reNative=RegExp("^"+String(toString).replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/toString| for [^\]]+/g,".*?")+"$");var ceil=Math.ceil,clearTimeout=context.clearTimeout,floor=Math.floor,fnToString=Function.prototype.toString,getPrototypeOf=isNative(getPrototypeOf=Object.getPrototypeOf)&&getPrototypeOf,hasOwnProperty=objectProto.hasOwnProperty,push=arrayRef.push,setTimeout=context.setTimeout,splice=arrayRef.splice,unshift=arrayRef.unshift;var defineProperty=function(){try{var o
 ={},func=isNative(func=Object.defineProperty)&&func,result=func(o,o,o)&&func}catch(e){}return result}();var nativeCreate=isNative(nativeCreate=Object.create)&&nativeCreate,nativeIsArray=isNative(nativeIsArray=Array.isArray)&&nativeIsArray,nativeIsFinite=context.isFinite,nativeIsNaN=context.isNaN,nativeKeys=isNative(nativeKeys=Object.keys)&&nativeKeys,nativeMax=Math.max,nativeMin=Math.min,nativeParseInt=context.parseInt,nativeRandom=Math.random;var ctorByClass={};ctorByClass[arrayClass]=Array;ctorByClass[boolClass]=Boolean;ctorByClass[dateClass]=Date;ctorByClass[funcClass]=Function;ctorByClass[objectClass]=Object;ctorByClass[numberClass]=Number;ctorByClass[regexpClass]=RegExp;ctorByClass[stringClass]=String;function lodash(value){return value&&typeof value=="object"&&!isArray(value)&&hasOwnProperty.call(value,"__wrapped__")?value:new lodashWrapper(value)}function lodashWrapper(value,chainAll){this.__chain__=!!chainAll;this.__wrapped__=value}lodashWrapper.prototype=lodash.prototype;va
 r support=lodash.support={};support.funcDecomp=!isNative(context.WinRTError)&&reThis.test(runInContext);support.funcNames=typeof Function.name=="string";lodash.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:reInterpolate,variable:"",imports:{_:lodash}};function baseBind(bindData){var func=bindData[0],partialArgs=bindData[2],thisArg=bindData[4];function bound(){if(partialArgs){var args=slice(partialArgs);push.apply(args,arguments)}if(this instanceof bound){var thisBinding=baseCreate(func.prototype),result=func.apply(thisBinding,args||arguments);return isObject(result)?result:thisBinding}return func.apply(thisArg,args||arguments)}setBindData(bound,bindData);return bound}function baseClone(value,isDeep,callback,stackA,stackB){if(callback){var result=callback(value);if(typeof result!="undefined"){return result}}var isObj=isObject(value);if(isObj){var className=toString.call(value);if(!cloneableClasses[className]){return value}var ctor=ctorByClass[clas
 sName];switch(className){case boolClass:case dateClass:return new ctor(+value);case numberClass:case stringClass:return new ctor(value);case regexpClass:result=ctor(value.source,reFlags.exec(value));result.lastIndex=value.lastIndex;return result}}else{return value}var isArr=isArray(value);if(isDeep){var initedStack=!stackA;stackA||(stackA=getArray());stackB||(stackB=getArray());var length=stackA.length;while(length--){if(stackA[length]==value){return stackB[length]}}result=isArr?ctor(value.length):{}}else{result=isArr?slice(value):assign({},value)}if(isArr){if(hasOwnProperty.call(value,"index")){result.index=value.index}if(hasOwnProperty.call(value,"input")){result.input=value.input}}if(!isDeep){return result}stackA.push(value);stackB.push(result);(isArr?forEach:forOwn)(value,function(objValue,key){result[key]=baseClone(objValue,isDeep,callback,stackA,stackB)});if(initedStack){releaseArray(stackA);releaseArray(stackB)}return result}function baseCreate(prototype,properties){return is
 Object(prototype)?nativeCreate(prototype):{}}if(!nativeCreate){baseCreate=function(){function Object(){}return function(prototype){if(isObject(prototype)){Object.prototype=prototype;var result=new Object;Object.prototype=null}return result||context.Object()}}()}function baseCreateCallback(func,thisArg,argCount){if(typeof func!="function"){return identity}if(typeof thisArg=="undefined"||!("prototype"in func)){return func}var bindData=func.__bindData__;if(typeof bindData=="undefined"){if(support.funcNames){bindData=!func.name}bindData=bindData||!support.funcDecomp;if(!bindData){var source=fnToString.call(func);if(!support.funcNames){bindData=!reFuncName.test(source)}if(!bindData){bindData=reThis.test(source);setBindData(func,bindData)}}}if(bindData===false||bindData!==true&&bindData[1]&1){return func}switch(argCount){case 1:return function(value){return func.call(thisArg,value)};case 2:return function(a,b){return func.call(thisArg,a,b)};case 3:return function(value,index,collection){r
 eturn func.call(thisArg,value,index,collection)};case 4:return function(accumulator,value,index,collection){return func.call(thisArg,accumulator,value,index,collection)}}return bind(func,thisArg)}function baseCreateWrapper(bindData){var func=bindData[0],bitmask=bindData[1],partialArgs=bindData[2],partialRightArgs=bindData[3],thisArg=bindData[4],arity=bindData[5];var isBind=bitmask&1,isBindKey=bitmask&2,isCurry=bitmask&4,isCurryBound=bitmask&8,key=func;function bound(){var thisBinding=isBind?thisArg:this;if(partialArgs){var args=slice(partialArgs);push.apply(args,arguments)}if(partialRightArgs||isCurry){args||(args=slice(arguments));if(partialRightArgs){push.apply(args,partialRightArgs)}if(isCurry&&args.length<arity){bitmask|=16&~32;return baseCreateWrapper([func,isCurryBound?bitmask:bitmask&~3,args,null,thisArg,arity])}}args||(args=arguments);if(isBindKey){func=thisBinding[key]}if(this instanceof bound){thisBinding=baseCreate(func.prototype);var result=func.apply(thisBinding,args);r
 eturn isObject(result)?result:thisBinding}return func.apply(thisBinding,args)}setBindData(bound,bindData);return bound}function baseDifference(array,values){var index=-1,indexOf=getIndexOf(),length=array?array.length:0,isLarge=length>=largeArraySize&&indexOf===baseIndexOf,result=[];if(isLarge){var cache=createCache(values);if(cache){indexOf=cacheIndexOf;values=cache}else{isLarge=false}}while(++index<length){var value=array[index];if(indexOf(values,value)<0){result.push(value)}}if(isLarge){releaseObject(values)}return result}function baseFlatten(array,isShallow,isStrict,fromIndex){var index=(fromIndex||0)-1,length=array?array.length:0,result=[];while(++index<length){var value=array[index];if(value&&typeof value=="object"&&typeof value.length=="number"&&(isArray(value)||isArguments(value))){if(!isShallow){value=baseFlatten(value,isShallow,isStrict)}var valIndex=-1,valLength=value.length,resIndex=result.length;result.length+=valLength;while(++valIndex<valLength){result[resIndex++]=valu
 e[valIndex]}}else if(!isStrict){result.push(value)}}return result}function baseIsEqual(a,b,callback,isWhere,stackA,stackB){if(callback){var result=callback(a,b);if(typeof result!="undefined"){return!!result}}if(a===b){return a!==0||1/a==1/b}var type=typeof a,otherType=typeof b;if(a===a&&!(a&&objectTypes[type])&&!(b&&objectTypes[otherType])){return false}if(a==null||b==null){return a===b}var className=toString.call(a),otherClass=toString.call(b);if(className==argsClass){className=objectClass}if(otherClass==argsClass){otherClass=objectClass}if(className!=otherClass){return false}switch(className){case boolClass:case dateClass:return+a==+b;case numberClass:return a!=+a?b!=+b:a==0?1/a==1/b:a==+b;case regexpClass:case stringClass:return a==String(b)}var isArr=className==arrayClass;if(!isArr){var aWrapped=hasOwnProperty.call(a,"__wrapped__"),bWrapped=hasOwnProperty.call(b,"__wrapped__");if(aWrapped||bWrapped){return baseIsEqual(aWrapped?a.__wrapped__:a,bWrapped?b.__wrapped__:b,callback,is
 Where,stackA,stackB)}if(className!=objectClass){return false}var ctorA=a.constructor,ctorB=b.constructor;if(ctorA!=ctorB&&!(isFunction(ctorA)&&ctorA instanceof ctorA&&isFunction(ctorB)&&ctorB instanceof ctorB)&&("constructor"in a&&"constructor"in b)){return false}}var initedStack=!stackA;stackA||(stackA=getArray());stackB||(stackB=getArray());var length=stackA.length;while(length--){if(stackA[length]==a){return stackB[length]==b}}var size=0;result=true;stackA.push(a);stackB.push(b);if(isArr){length=a.length;size=b.length;result=size==length;if(result||isWhere){while(size--){var index=length,value=b[size];if(isWhere){while(index--){if(result=baseIsEqual(a[index],value,callback,isWhere,stackA,stackB)){break}}}else if(!(result=baseIsEqual(a[size],value,callback,isWhere,stackA,stackB))){break}}}}else{forIn(b,function(value,key,b){if(hasOwnProperty.call(b,key)){size++;return result=hasOwnProperty.call(a,key)&&baseIsEqual(a[key],value,callback,isWhere,stackA,stackB)}});if(result&&!isWhere
 ){forIn(a,function(value,key,a){if(hasOwnProperty.call(a,key)){return result=--size>-1}})}}stackA.pop();stackB.pop();if(initedStack){releaseArray(stackA);releaseArray(stackB)}return result}function baseMerge(object,source,callback,stackA,stackB){(isArray(source)?forEach:forOwn)(source,function(source,key){var found,isArr,result=source,value=object[key];if(source&&((isArr=isArray(source))||isPlainObject(source))){var stackLength=stackA.length;while(stackLength--){if(found=stackA[stackLength]==source){value=stackB[stackLength];break}}if(!found){var isShallow;if(callback){result=callback(value,source);if(isShallow=typeof result!="undefined"){value=result}}if(!isShallow){value=isArr?isArray(value)?value:[]:isPlainObject(value)?value:{}}stackA.push(source);stackB.push(value);if(!isShallow){baseMerge(value,source,callback,stackA,stackB)}}}else{if(callback){result=callback(value,source);if(typeof result=="undefined"){result=source}}if(typeof result!="undefined"){value=result}}object[key]=v
 alue})}function baseRandom(min,max){return min+floor(nativeRandom()*(max-min+1))}function baseUniq(array,isSorted,callback){var index=-1,indexOf=getIndexOf(),length=array?array.length:0,result=[];var isLarge=!isSorted&&length>=largeArraySize&&indexOf===baseIndexOf,seen=callback||isLarge?getArray():result;if(isLarge){var cache=createCache(seen);indexOf=cacheIndexOf;seen=cache}while(++index<length){var value=array[index],computed=callback?callback(value,index,array):value;if(isSorted?!index||seen[seen.length-1]!==computed:indexOf(seen,computed)<0){if(callback||isLarge){seen.push(computed)}result.push(value)}}if(isLarge){releaseArray(seen.array);releaseObject(seen)}else if(callback){releaseArray(seen)}return result}function createAggregator(setter){return function(collection,callback,thisArg){var result={};callback=lodash.createCallback(callback,thisArg,3);var index=-1,length=collection?collection.length:0;if(typeof length=="number"){while(++index<length){var value=collection[index];se
 tter(result,value,callback(value,index,collection),collection)}}else{forOwn(collection,function(value,key,collection){setter(result,value,callback(value,key,collection),collection)})}return result}}function createWrapper(func,bitmask,partialArgs,partialRightArgs,thisArg,arity){var isBind=bitmask&1,isBindKey=bitmask&2,isCurry=bitmask&4,isCurryBound=bitmask&8,isPartial=bitmask&16,isPartialRight=bitmask&32;if(!isBindKey&&!isFunction(func)){throw new TypeError}if(isPartial&&!partialArgs.length){bitmask&=~16;isPartial=partialArgs=false}if(isPartialRight&&!partialRightArgs.length){bitmask&=~32;isPartialRight=partialRightArgs=false}var bindData=func&&func.__bindData__;if(bindData&&bindData!==true){bindData=slice(bindData);if(bindData[2]){bindData[2]=slice(bindData[2])}if(bindData[3]){bindData[3]=slice(bindData[3])}if(isBind&&!(bindData[1]&1)){bindData[4]=thisArg}if(!isBind&&bindData[1]&1){bitmask|=8}if(isCurry&&!(bindData[1]&4)){bindData[5]=arity}if(isPartial){push.apply(bindData[2]||(bind
 Data[2]=[]),partialArgs)}if(isPartialRight){unshift.apply(bindData[3]||(bindData[3]=[]),partialRightArgs)}bindData[1]|=bitmask;return createWrapper.apply(null,bindData)}var creater=bitmask==1||bitmask===17?baseBind:baseCreateWrapper;return creater([func,bitmask,partialArgs,partialRightArgs,thisArg,arity])}function escapeHtmlChar(match){return htmlEscapes[match]}function getIndexOf(){var result=(result=lodash.indexOf)===indexOf?baseIndexOf:result;return result}function isNative(value){return typeof value=="function"&&reNative.test(value)}var setBindData=!defineProperty?noop:function(func,value){descriptor.value=value;defineProperty(func,"__bindData__",descriptor)};function shimIsPlainObject(value){var ctor,result;if(!(value&&toString.call(value)==objectClass)||(ctor=value.constructor,isFunction(ctor)&&!(ctor instanceof ctor))){return false}forIn(value,function(value,key){result=key});return typeof result=="undefined"||hasOwnProperty.call(value,result)}function unescapeHtmlChar(match)
 {return htmlUnescapes[match]}function isArguments(value){return value&&typeof value=="object"&&typeof value.length=="number"&&toString.call(value)==argsClass||false}var isArray=nativeIsArray||function(value){return value&&typeof value=="object"&&typeof value.length=="number"&&toString.call(value)==arrayClass||false};var shimKeys=function(object){var index,iterable=object,result=[];if(!iterable)return result;if(!objectTypes[typeof object])return result;for(index in iterable){if(hasOwnProperty.call(iterable,index)){result.push(index)}}return result};var keys=!nativeKeys?shimKeys:function(object){if(!isObject(object)){return[]}return nativeKeys(object)};var htmlEscapes={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};var htmlUnescapes=invert(htmlEscapes);var reEscapedHtml=RegExp("("+keys(htmlUnescapes).join("|")+")","g"),reUnescapedHtml=RegExp("["+keys(htmlEscapes).join("")+"]","g");var assign=function(object,source,guard){var index,iterable=object,result=iterable;if(!itera
 ble)return result;var args=arguments,argsIndex=0,argsLength=typeof guard=="number"?2:args.length;if(argsLength>3&&typeof args[argsLength-2]=="function"){var callback=baseCreateCallback(args[--argsLength-1],args[argsLength--],2)}else if(argsLength>2&&typeof args[argsLength-1]=="function"){callback=args[--argsLength]}while(++argsIndex<argsLength){iterable=args[argsIndex];if(iterable&&objectTypes[typeof iterable]){var ownIndex=-1,ownProps=objectTypes[typeof iterable]&&keys(iterable),length=ownProps?ownProps.length:0;while(++ownIndex<length){index=ownProps[ownIndex];result[index]=callback?callback(result[index],iterable[index]):iterable[index]}}}return result};function clone(value,isDeep,callback,thisArg){if(typeof isDeep!="boolean"&&isDeep!=null){thisArg=callback;callback=isDeep;isDeep=false}return baseClone(value,isDeep,typeof callback=="function"&&baseCreateCallback(callback,thisArg,1))}function cloneDeep(value,callback,thisArg){return baseClone(value,true,typeof callback=="function"
 &&baseCreateCallback(callback,thisArg,1))}function create(prototype,properties){var result=baseCreate(prototype);return properties?assign(result,properties):result}var defaults=function(object,source,guard){var index,iterable=object,result=iterable;if(!iterable)return result;var args=arguments,argsIndex=0,argsLength=typeof guard=="number"?2:args.length;while(++argsIndex<argsLength){iterable=args[argsIndex];if(iterable&&objectTypes[typeof iterable]){var ownIndex=-1,ownProps=objectTypes[typeof iterable]&&keys(iterable),length=ownProps?ownProps.length:0;while(++ownIndex<length){index=ownProps[ownIndex];if(typeof result[index]=="undefined")result[index]=iterable[index]}}}return result};function findKey(object,callback,thisArg){var result;callback=lodash.createCallback(callback,thisArg,3);forOwn(object,function(value,key,object){if(callback(value,key,object)){result=key;return false}});return result}function findLastKey(object,callback,thisArg){var result;callback=lodash.createCallback(c
 allback,thisArg,3);forOwnRight(object,function(value,key,object){if(callback(value,key,object)){result=key;return false}});return result}var forIn=function(collection,callback,thisArg){var index,iterable=collection,result=iterable;if(!iterable)return result;if(!objectTypes[typeof iterable])return result;callback=callback&&typeof thisArg=="undefined"?callback:baseCreateCallback(callback,thisArg,3);for(index in iterable){if(callback(iterable[index],index,collection)===false)return result}return result};function forInRight(object,callback,thisArg){var pairs=[];forIn(object,function(value,key){pairs.push(key,value)});var length=pairs.length;callback=baseCreateCallback(callback,thisArg,3);while(length--){if(callback(pairs[length--],pairs[length],object)===false){break}}return object}var forOwn=function(collection,callback,thisArg){var index,iterable=collection,result=iterable;if(!iterable)return result;if(!objectTypes[typeof iterable])return result;callback=callback&&typeof thisArg=="und
 efined"?callback:baseCreateCallback(callback,thisArg,3);var ownIndex=-1,ownProps=objectTypes[typeof iterable]&&keys(iterable),length=ownProps?ownProps.length:0;while(++ownIndex<length){index=ownProps[ownIndex];if(callback(iterable[index],index,collection)===false)return result}return result};function forOwnRight(object,callback,thisArg){var props=keys(object),length=props.length;callback=baseCreateCallback(callback,thisArg,3);while(length--){var key=props[length];if(callback(object[key],key,object)===false){break}}return object}function functions(object){var result=[];forIn(object,function(value,key){if(isFunction(value)){result.push(key)}});return result.sort()}function has(object,key){return object?hasOwnProperty.call(object,key):false}function invert(object){var index=-1,props=keys(object),length=props.length,result={};while(++index<length){var key=props[index];result[object[key]]=key}return result}function isBoolean(value){return value===true||value===false||value&&typeof value=
 ="object"&&toString.call(value)==boolClass||false}function isDate(value){return value&&typeof value=="object"&&toString.call(value)==dateClass||false}function isElement(value){return value&&value.nodeType===1||false}function isEmpty(value){var result=true;if(!value){return result}var className=toString.call(value),length=value.length;if(className==arrayClass||className==stringClass||className==argsClass||className==objectClass&&typeof length=="number"&&isFunction(value.splice)){return!length}forOwn(value,function(){return result=false});return result}function isEqual(a,b,callback,thisArg){return baseIsEqual(a,b,typeof callback=="function"&&baseCreateCallback(callback,thisArg,2))}function isFinite(value){return nativeIsFinite(value)&&!nativeIsNaN(parseFloat(value))}function isFunction(value){return typeof value=="function"}function isObject(value){return!!(value&&objectTypes[typeof value])}function isNaN(value){return isNumber(value)&&value!=+value}function isNull(value){return value
 ===null}function isNumber(value){return typeof value=="number"||value&&typeof value=="object"&&toString.call(value)==numberClass||false}var isPlainObject=!getPrototypeOf?shimIsPlainObject:function(value){if(!(value&&toString.call(value)==objectClass)){return false}var valueOf=value.valueOf,objProto=isNative(valueOf)&&(objProto=getPrototypeOf(valueOf))&&getPrototypeOf(objProto);return objProto?value==objProto||getPrototypeOf(value)==objProto:shimIsPlainObject(value)};function isRegExp(value){return value&&typeof value=="object"&&toString.call(value)==regexpClass||false}function isString(value){return typeof value=="string"||value&&typeof value=="object"&&toString.call(value)==stringClass||false}function isUndefined(value){return typeof value=="undefined"}function mapValues(object,callback,thisArg){var result={};callback=lodash.createCallback(callback,thisArg,3);forOwn(object,function(value,key,object){result[key]=callback(value,key,object)});return result}function merge(object){var a
 rgs=arguments,length=2;if(!isObject(object)){return object}if(typeof args[2]!="number"){length=args.length}if(length>3&&typeof args[length-2]=="function"){var callback=baseCreateCallback(args[--length-1],args[length--],2)}else if(length>2&&typeof args[length-1]=="function"){callback=args[--length]}var sources=slice(arguments,1,length),index=-1,stackA=getArray(),stackB=getArray();while(++index<length){baseMerge(object,sources[index],callback,stackA,stackB)}releaseArray(stackA);releaseArray(stackB);return object}function omit(object,callback,thisArg){var result={};if(typeof callback!="function"){var props=[];forIn(object,function(value,key){props.push(key)});props=baseDifference(props,baseFlatten(arguments,true,false,1));var index=-1,length=props.length;while(++index<length){var key=props[index];result[key]=object[key]}}else{callback=lodash.createCallback(callback,thisArg,3);forIn(object,function(value,key,object){if(!callback(value,key,object)){result[key]=value}})}return result}func
 tion pairs(object){var index=-1,props=keys(object),length=props.length,result=Array(length);while(++index<length){var key=props[index];result[index]=[key,object[key]]}return result}function pick(object,callback,thisArg){var result={};if(typeof

<TRUNCATED>

[27/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/app.js
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/app.js b/ambari-server/src/main/resources/app.js
new file mode 100644
index 0000000..901a697
--- /dev/null
+++ b/ambari-server/src/main/resources/app.js
@@ -0,0 +1,219702 @@
+(function() {
+  'use strict';
+
+  var globals = typeof window === 'undefined' ? global : window;
+  if (typeof globals.require === 'function') return;
+
+  var modules = {};
+  var cache = {};
+  var has = ({}).hasOwnProperty;
+
+  var aliases = {};
+
+  var endsWith = function(str, suffix) {
+    return str.indexOf(suffix, str.length - suffix.length) !== -1;
+  };
+
+  var unalias = function(alias, loaderPath) {
+    var start = 0;
+    if (loaderPath) {
+      if (loaderPath.indexOf('components/' === 0)) {
+        start = 'components/'.length;
+      }
+      if (loaderPath.indexOf('/', start) > 0) {
+        loaderPath = loaderPath.substring(start, loaderPath.indexOf('/', start));
+      }
+    }
+    var result = aliases[alias + '/index.js'] || aliases[loaderPath + '/deps/' + alias + '/index.js'];
+    if (result) {
+      return 'components/' + result.substring(0, result.length - '.js'.length);
+    }
+    return alias;
+  };
+
+  var expand = (function() {
+    var reg = /^\.\.?(\/|$)/;
+    return function(root, name) {
+      var results = [], parts, part;
+      parts = (reg.test(name) ? root + '/' + name : name).split('/');
+      for (var i = 0, length = parts.length; i < length; i++) {
+        part = parts[i];
+        if (part === '..') {
+          results.pop();
+        } else if (part !== '.' && part !== '') {
+          results.push(part);
+        }
+      }
+      return results.join('/');
+    };
+  })();
+  var dirname = function(path) {
+    return path.split('/').slice(0, -1).join('/');
+  };
+
+  var localRequire = function(path) {
+    return function(name) {
+      var absolute = expand(dirname(path), name);
+      return globals.require(absolute, path);
+    };
+  };
+
+  var initModule = function(name, definition) {
+    var module = {id: name, exports: {}};
+    cache[name] = module;
+    definition(module.exports, localRequire(name), module);
+    return module.exports;
+  };
+
+  var require = function(name, loaderPath) {
+    var path = expand(name, '.');
+    if (loaderPath == null) loaderPath = '/';
+    path = unalias(name, loaderPath);
+
+    if (has.call(cache, path)) return cache[path].exports;
+    if (has.call(modules, path)) return initModule(path, modules[path]);
+
+    var dirIndex = expand(path, './index');
+    if (has.call(cache, dirIndex)) return cache[dirIndex].exports;
+    if (has.call(modules, dirIndex)) return initModule(dirIndex, modules[dirIndex]);
+
+    throw new Error('Cannot find module "' + name + '" from '+ '"' + loaderPath + '"');
+  };
+
+  require.alias = function(from, to) {
+    aliases[to] = from;
+  };
+
+  require.register = require.define = function(bundle, fn) {
+    if (typeof bundle === 'object') {
+      for (var key in bundle) {
+        if (has.call(bundle, key)) {
+          modules[key] = bundle[key];
+        }
+      }
+    } else {
+      modules[bundle] = fn;
+    }
+  };
+
+  require.list = function() {
+    var result = [];
+    for (var item in modules) {
+      if (has.call(modules, item)) {
+        result.push(item);
+      }
+    }
+    return result;
+  };
+
+  require.brunch = true;
+  globals.require = require;
+})();
+require.register("app", function(exports, require, module) {
+/**
+ * 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.
+ */
+
+// Application bootstrapper
+require('utils/ember_reopen');
+require('utils/ember_computed');
+var stringUtils = require('utils/string_utils');
+
+module.exports = Em.Application.create({
+  name: 'Ambari Web',
+  rootElement: '#wrapper',
+
+  store: DS.Store.create({
+    revision: 4,
+    adapter: DS.FixtureAdapter.create({
+      simulateRemoteResponse: false
+    }),
+    typeMaps: {},
+    recordCache: []
+  }),
+  isAdmin: false,
+  isOperator: false,
+  isClusterUser: false,
+  isPermissionDataLoaded: false,
+  auth: null,
+  isOnlyViewUser: function() {
+    return App.auth && (App.auth.length == 0 || (App.isAuthorized('VIEW.USE') && App.auth.length == 1));
+  }.property('auth'),
+
+  /**
+   * @type {boolean}
+   * @default false
+   */
+  isKerberosEnabled: false,
+
+  /**
+   * state of stack upgrade process
+   * states:
+   *  - INIT
+   *  - PENDING
+   *  - IN_PROGRESS
+   *  - HOLDING
+   *  - COMPLETED
+   *  - ABORTED
+   *  - HOLDING_FAILED
+   *  - HOLDING_TIMEDOUT
+   * @type {String}
+   */
+  upgradeState: 'INIT',
+
+  /**
+   * flag is true when upgrade process is running
+   * @returns {boolean}
+   */
+  upgradeInProgress: Em.computed.equal('upgradeState', 'IN_PROGRESS'),
+
+  /**
+   * flag is true when upgrade process is waiting for user action
+   * to proceed, retry, perform manual steps etc.
+   * @returns {boolean}
+   */
+  upgradeHolding: function() {
+    return this.get('upgradeState').contains("HOLDING") || this.get('upgradeAborted');
+  }.property('upgradeState', 'upgradeAborted'),
+
+  /**
+   * flag is true when upgrade process is aborted
+   * SHOULD behave similar to HOLDING_FAILED state
+   * @returns {boolean}
+   */
+  upgradeAborted: function () {
+    return this.get('upgradeState') === "ABORTED" && !App.router.get('mainAdminStackAndUpgradeController.isSuspended');
+  }.property('upgradeState', 'App.router.mainAdminStackAndUpgradeController.isSuspended'),
+
+  /**
+   * flag is true when upgrade process is suspended
+   * @returns {boolean}
+   */
+  upgradeSuspended: function () {
+    return this.get('upgradeState') === "ABORTED" && App.router.get('mainAdminStackAndUpgradeController.isSuspended');
+  }.property('upgradeState', 'App.router.mainAdminStackAndUpgradeController.isSuspended'),
+
+  /**
+   * RU is running
+   * @type {boolean}
+   */
+  upgradeIsRunning: Em.computed.or('upgradeInProgress', 'upgradeHolding'),
+
+  /**
+   * flag is true when upgrade process is running or suspended
+   * or wizard used by another user
+   * @returns {boolean}
+   */
+  wizardIsNotFinished: function () {
+    return this.get('upgradeIsRunning') ||
+           this.get('upgradeSuspended') ||
+           App.router.get('wizardWatcherController.isNonWizardUser');
+  }.property('upgradeIsRunning', 'upgradeAborted', 'router.wizardWatcherController.isNonWizardUser', 'upgradeSuspended'),
+
+  /**
+   * Options:
+   *  - ignoreWizard: ignore when some wizard is running by another user (default `false`)
+   *
+   * @param {string} authRoles
+   * @param {object} options
+   * @returns {boolean}
+   */
+  isAuthorized: function(authRoles, options) {
+    options = $.extend({ignoreWizard: false}, options);
+    var result = false;
+    authRoles = $.map(authRoles.split(","), $.trim);
+
+    if (!this.get('upgradeSuspended') &&
+        !App.get('supports.opsDuringRollingUpgrade') &&
+        !['INIT', 'COMPLETED'].contains(this.get('upgradeState')) ||
+        !App.auth){
+      return false;
+    }
+
+    if (!options.ignoreWizard && App.router.get('wizardWatcherController.isNonWizardUser')) {
+      return false;
+    }
+
+    authRoles.forEach(function(auth) {
+      result = result || App.auth.contains(auth);
+    });
+
+    return result;
+  },
+
+  isStackServicesLoaded: false,
+  /**
+   * return url prefix with number value of version of HDP stack
+   */
+  stackVersionURL: function () {
+    return '/stacks/{0}/versions/{1}'.format(this.get('currentStackName') || 'HDP', this.get('currentStackVersionNumber'));
+  }.property('currentStackName','currentStackVersionNumber'),
+
+  falconServerURL: function () {
+    var falconService = this.Service.find().findProperty('serviceName', 'FALCON');
+    if (falconService) {
+      return falconService.get('hostComponents').findProperty('componentName', 'FALCON_SERVER').get('hostName');
+    }
+    return '';
+  }.property().volatile(),
+
+  /* Determine if Application Timeline Service supports Kerberization.
+   * Because this value is retrieved from the cardinality of the component, it is safe to keep in app.js
+   * since its value will not change during the lifetime of the application.
+   */
+  doesATSSupportKerberos: function() {
+    var YARNService = App.StackServiceComponent.find().filterProperty('serviceName', 'YARN');
+    if (YARNService.length) {
+      var ATS = App.StackServiceComponent.find().findProperty('componentName', 'APP_TIMELINE_SERVER');
+      return (!!ATS && !!ATS.get('minToInstall'));
+    }
+    return false;
+  }.property('router.clusterController.isLoaded'),
+
+  clusterName: null,
+  clockDistance: null, // server clock - client clock
+  currentStackVersion: '',
+  currentStackName: function() {
+    return Em.get((this.get('currentStackVersion') || this.get('defaultStackVersion')).match(/(.+)-\d.+/), '1');
+  }.property('currentStackVersion', 'defaultStackVersion'),
+
+  /**
+   * true if cluster has only 1 host
+   * for now is used to disable move/HA actions
+   * @type {boolean}
+   */
+  isSingleNode: Em.computed.equal('allHostNames.length', 1),
+
+  allHostNames: [],
+
+  /**
+   * This object is populated to keep track of uninstalled components to be included in the layout for recommendation/validation call
+   * @type {object}
+   * keys = componentName, hostName
+   */
+  componentToBeAdded: {},
+
+
+  /**
+   * This object is populated to keep track of installed components to be excluded in the layout for recommendation/validation call
+   * @type {object}
+   * keys = componentName, hostName
+   */
+  componentToBeDeleted: {},
+
+  uiOnlyConfigDerivedFromTheme: [],
+
+  currentStackVersionNumber: function () {
+    var regExp = new RegExp(this.get('currentStackName') + '-');
+    return (this.get('currentStackVersion') || this.get('defaultStackVersion')).replace(regExp, '');
+  }.property('currentStackVersion', 'defaultStackVersion', 'currentStackName'),
+
+  isHadoop23Stack: function () {
+    return (stringUtils.compareVersions(this.get('currentStackVersionNumber'), "2.3") > -1);
+  }.property('currentStackVersionNumber'),
+
+  isHadoopWindowsStack: Em.computed.equal('currentStackName', 'HDPWIN'),
+
+  /**
+   * If NameNode High Availability is enabled
+   * Based on <code>clusterStatus.isInstalled</code>, stack version, <code>SNameNode</code> availability
+   *
+   * @type {bool}
+   */
+  isHaEnabled: function () {
+    return App.Service.find('HDFS').get('isLoaded') && !App.HostComponent.find().someProperty('componentName', 'SECONDARY_NAMENODE');
+  }.property('router.clusterController.dataLoadList.services', 'router.clusterController.isServiceContentFullyLoaded'),
+
+  /**
+   * If ResourceManager High Availability is enabled
+   * Based on number of ResourceManager host components installed
+   *
+   * @type {bool}
+   */
+  isRMHaEnabled: function () {
+    var result = false;
+    var rmStackComponent = App.StackServiceComponent.find().findProperty('componentName','RESOURCEMANAGER');
+    if (rmStackComponent && rmStackComponent.get('isMultipleAllowed')) {
+      result = this.HostComponent.find().filterProperty('componentName', 'RESOURCEMANAGER').length > 1;
+    }
+    return result;
+  }.property('router.clusterController.isLoaded', 'isStackServicesLoaded'),
+
+  /**
+   * If Ranger Admin High Availability is enabled
+   * Based on number of Ranger Admin host components installed
+   *
+   * @type {bool}
+   */
+  isRAHaEnabled: function () {
+    var result = false;
+    var raStackComponent = App.StackServiceComponent.find().findProperty('componentName','RANGER_ADMIN');
+    if (raStackComponent && raStackComponent.get('isMultipleAllowed')) {
+      result = App.HostComponent.find().filterProperty('componentName', 'RANGER_ADMIN').length > 1;
+    }
+    return result;
+  }.property('router.clusterController.isLoaded', 'isStackServicesLoaded'),
+
+  /**
+   * Object with utility functions for list of service names with similar behavior
+   */
+  services: Em.Object.create({
+    all: function () {
+      return App.StackService.find().mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
+
+    clientOnly: function () {
+      return App.StackService.find().filterProperty('isClientOnlyService').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
+
+    hasClient: function () {
+      return App.StackService.find().filterProperty('hasClient').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
+
+    hasMaster: function () {
+      return App.StackService.find().filterProperty('hasMaster').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
+
+    hasSlave: function () {
+      return App.StackService.find().filterProperty('hasSlave').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
+
+    noConfigTypes: function () {
+      return App.StackService.find().filterProperty('isNoConfigTypes').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
+
+    servicesWithHeatmapTab: function () {
+      return App.StackService.find().filterProperty('hasHeatmapSection').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
+
+    monitoring: function () {
+      return App.StackService.find().filterProperty('isMonitoringService').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
+
+    hostMetrics: function () {
+      return App.StackService.find().filterProperty('isHostMetricsService').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
+
+    serviceMetrics: function () {
+      return App.StackService.find().filterProperty('isServiceMetricsService').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded'),
+
+    supportsServiceCheck: function() {
+      return App.StackService.find().filterProperty('serviceCheckSupported').mapProperty('serviceName');
+    }.property('App.router.clusterController.isLoaded')
+  }),
+
+  /**
+   * List of components with allowed action for them
+   * @type {Em.Object}
+   */
+  components: Em.Object.create({
+    allComponents: function () {
+      return App.StackServiceComponent.find().mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    reassignable: function () {
+      return App.StackServiceComponent.find().filterProperty('isReassignable').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    restartable: function () {
+      return App.StackServiceComponent.find().filterProperty('isRestartable').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    deletable: function () {
+      return App.StackServiceComponent.find().filterProperty('isDeletable').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    rollinRestartAllowed: function () {
+      return App.StackServiceComponent.find().filterProperty('isRollinRestartAllowed').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    decommissionAllowed: function () {
+      return App.StackServiceComponent.find().filterProperty('isDecommissionAllowed').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    refreshConfigsAllowed: function () {
+      return App.StackServiceComponent.find().filterProperty('isRefreshConfigsAllowed').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    addableToHost: function () {
+      return App.StackServiceComponent.find().filterProperty('isAddableToHost').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    addableMasterInstallerWizard: function () {
+      return App.StackServiceComponent.find().filterProperty('isMasterAddableInstallerWizard').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    multipleMasters: function () {
+      return App.StackServiceComponent.find().filterProperty('isMasterWithMultipleInstances').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    slaves: function () {
+      return App.StackServiceComponent.find().filterProperty('isSlave').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    masters: function () {
+      return App.StackServiceComponent.find().filterProperty('isMaster').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    clients: function () {
+      return App.StackServiceComponent.find().filterProperty('isClient').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded'),
+
+    nonHDP: function () {
+      return App.StackServiceComponent.find().filterProperty('isNonHDPComponent').mapProperty('componentName')
+    }.property('App.router.clusterController.isLoaded')
+  })
+});
+
+});
+
+require.register("config", function(exports, require, module) {
+/**
+ * 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 = require('app');
+
+App.version = '2.4.0.0'; // filled out by set-ambari-version.sh script
+App.testMode = (location.port == '3333'); // test mode is automatically enabled if running on brunch server
+App.testModeDelayForActions = 10000;
+App.skipBootstrap = false;
+App.alwaysGoToInstaller = false;
+App.testEnableSecurity = true; // By default enable security is tested; turning it false tests disable security
+App.testNameNodeHA = true;
+App.apiPrefix = '/api/v2';
+App.defaultStackVersion = 'HDP-2.5';
+App.defaultWindowsStackVersion = 'HDPWIN-2.1';
+
+App.defaultJavaHome = '/usr/jdk/jdk1.6.0_31';
+App.timeout = 180000; // default AJAX timeout
+App.maxRetries = 3; // max number of retries for certain AJAX calls
+App.sessionKeepAliveInterval  = 60000;
+App.bgOperationsUpdateInterval = 6000;
+App.componentsUpdateInterval = 6000;
+App.contentUpdateInterval = 15000;
+App.hostStatusCountersUpdateInterval = 10000;
+App.alertDefinitionsUpdateInterval = 10000;
+App.alertInstancesUpdateInterval = 10000;
+App.alertGroupsUpdateInterval = 10000;
+App.clusterEnvUpdateInterval = 10000;
+App.pageReloadTime = 3600000;
+App.nnCheckpointAgeAlertThreshold = 12; // in hours
+App.singleNodeInstall = false;
+App.singleNodeAlias = document.location.hostname;
+App.minDiskSpace = 2.0; // minimum disk space required for '/' for each host before install, unit GB
+App.minDiskSpaceUsrLib = 1.0; // minimum disk space for '/usr/lib' for each host before install, unit GB
+App.healthIconClassGreen = 'icon-ok-sign'; // bootstrap icon class for healthy/started service/host/host-component
+App.healthIconClassRed = 'icon-warning-sign'; // bootstrap icon class for master down/stopped service/host/host-component
+App.healthIconClassOrange = 'icon-minus-sign'; // bootstrap icon class for slave down/decommissioned host/host-component
+App.healthIconClassYellow = 'icon-question-sign'; // bootstrap icon class for heartbeat lost service/host/host-component
+App.isManagedMySQLForHiveEnabled = false;
+App.isStormMetricsSupported = true;
+App.healthStatusRed = '#ff0000';
+App.healthStatusGreen = '#5AB400';
+App.healthStatusOrange = '#FF8E00';
+App.inactivityRemainTime = 60; // in seconds
+
+App.stackVersionsAvailable = true;
+
+// experimental features are automatically enabled if running on brunch server
+App.enableExperimental = false;
+
+App.supports = {
+  preUpgradeCheck: true,
+  displayOlderVersions: false,
+  autoRollbackHA: false,
+  alwaysEnableManagedMySQLForHive: false,
+  preKerberizeCheck: false,
+  customizeAgentUserAccount: false,
+  installGanglia: false,
+  opsDuringRollingUpgrade: false,
+  customizedWidgetLayout: false,
+  showPageLoadTime: false,
+  skipComponentStartAfterInstall: false,
+  preInstallChecks: false,
+  hostComboSearchBox: true,
+  serviceAutoStart: false,
+  logSearch: true,
+  redhatSatellite: false,
+  enableIpa: false,
+  addingNewRepository: false,
+  kerberosStackAdvisor: true,
+  logCountVizualization: false
+};
+
+if (App.enableExperimental) {
+  for (var support in App.supports) {
+    App.supports[support] = true;
+  }
+}
+
+// this is to make sure that IE does not cache data when making AJAX calls to the server
+if (!$.mocho) {
+  $.ajaxSetup({
+    cache: false,
+    headers: {"X-Requested-By": "X-Requested-By"}
+  });
+}
+
+/**
+ * Test Mode values
+ */
+App.test_hostname = 'hostname';
+
+});
+
+require.register("controllers", function(exports, require, module) {
+/**
+ * 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.
+ */
+
+
+// load all controllers here
+
+require('controllers/application');
+require('controllers/login_controller');
+require('controllers/wizard');
+require('controllers/installer');
+require('controllers/experimental');
+require('controllers/global/background_operations_controller');
+require('controllers/global/wizard_watcher_controller');
+require('controllers/global/user_settings_controller');
+require('controllers/global/errors_handler_controller');
+require('controllers/main');
+require('controllers/main/dashboard');
+require('controllers/main/dashboard/config_history_controller');
+require('controllers/main/admin');
+require('controllers/main/admin/service_auto_start');
+require('controllers/main/admin/highAvailability_controller');
+require('controllers/main/admin/highAvailability/nameNode/wizard_controller');
+require('controllers/main/admin/highAvailability/progress_controller');
+require('controllers/main/admin/highAvailability/progress_popup_controller');
+require('controllers/main/admin/highAvailability/nameNode/rollback_controller');
+require('controllers/main/admin/highAvailability/nameNode/step1_controller');
+require('controllers/main/admin/highAvailability/nameNode/step2_controller');
+require('controllers/main/admin/highAvailability/nameNode/step3_controller');
+require('controllers/main/admin/highAvailability/nameNode/step4_controller');
+require('controllers/main/admin/highAvailability/nameNode/step5_controller');
+require('controllers/main/admin/highAvailability/nameNode/step6_controller');
+require('controllers/main/admin/highAvailability/nameNode/step7_controller');
+require('controllers/main/admin/highAvailability/nameNode/step8_controller');
+require('controllers/main/admin/highAvailability/nameNode/step9_controller');
+require('controllers/main/admin/highAvailability/nameNode/rollbackHA/step1_controller');
+require('controllers/main/admin/highAvailability/nameNode/rollbackHA/step2_controller');
+require('controllers/main/admin/highAvailability/nameNode/rollbackHA/step3_controller');
+require('controllers/main/admin/highAvailability/nameNode/rollbackHA/rollback_wizard_controller');
+require('controllers/main/admin/highAvailability/resourceManager/wizard_controller');
+require('controllers/main/admin/highAvailability/resourceManager/step1_controller');
+require('controllers/main/admin/highAvailability/resourceManager/step2_controller');
+require('controllers/main/admin/highAvailability/resourceManager/step3_controller');
+require('controllers/main/admin/highAvailability/resourceManager/step4_controller');
+require('controllers/main/admin/highAvailability/hawq/addStandby/wizard_controller');
+require('controllers/main/admin/highAvailability/hawq/addStandby/step1_controller');
+require('controllers/main/admin/highAvailability/hawq/addStandby/step2_controller');
+require('controllers/main/admin/highAvailability/hawq/addStandby/step3_controller');
+require('controllers/main/admin/highAvailability/hawq/addStandby/step4_controller');
+require('controllers/main/admin/highAvailability/hawq/removeStandby/wizard_controller');
+require('controllers/main/admin/highAvailability/hawq/removeStandby/step1_controller');
+require('controllers/main/admin/highAvailability/hawq/removeStandby/step2_controller');
+require('controllers/main/admin/highAvailability/hawq/removeStandby/step3_controller');
+require('controllers/main/admin/highAvailability/hawq/activateStandby/wizard_controller');
+require('controllers/main/admin/highAvailability/hawq/activateStandby/step1_controller');
+require('controllers/main/admin/highAvailability/hawq/activateStandby/step2_controller');
+require('controllers/main/admin/highAvailability/hawq/activateStandby/step3_controller');
+require('controllers/main/admin/highAvailability/rangerAdmin/wizard_controller');
+require('controllers/main/admin/highAvailability/rangerAdmin/step1_controller');
+require('controllers/main/admin/highAvailability/rangerAdmin/step2_controller');
+require('controllers/main/admin/highAvailability/rangerAdmin/step3_controller');
+require('controllers/main/admin/highAvailability/rangerAdmin/step4_controller');
+require('controllers/main/admin/stack_and_upgrade_controller');
+require('controllers/main/admin/serviceAccounts_controller');
+require('utils/polling');
+require('controllers/main/admin/kerberos');
+require('controllers/main/admin/kerberos/wizard_controller');
+require('controllers/main/admin/kerberos/disable_controller');
+require('controllers/main/admin/kerberos/progress_controller');
+require('controllers/main/admin/kerberos/step1_controller');
+require('controllers/main/admin/kerberos/step2_controller');
+require('controllers/main/admin/kerberos/step3_controller');
+require('controllers/main/admin/kerberos/step4_controller');
+require('controllers/main/admin/kerberos/step5_controller');
+require('controllers/main/admin/kerberos/step6_controller');
+require('controllers/main/admin/kerberos/step7_controller');
+require('controllers/main/admin/kerberos/step8_controller');
+require('controllers/main/alert_definitions_controller');
+require('controllers/main/alerts/alert_definitions_actions_controller');
+require('controllers/main/alerts/add_alert_definition/add_alert_definition_controller');
+require('controllers/main/alerts/add_alert_definition/step1_controller');
+require('controllers/main/alerts/add_alert_definition/step2_controller');
+require('controllers/main/alerts/add_alert_definition/step3_controller');
+require('controllers/main/alerts/definition_details_controller');
+require('controllers/main/alerts/definition_configs_controller');
+require('controllers/main/alerts/alert_instances_controller');
+require('controllers/main/alerts/manage_alert_groups_controller');
+require('controllers/main/alerts/manage_alert_notifications_controller');
+require('controllers/main/service');
+require('controllers/main/service/item');
+require('controllers/main/service/info/summary');
+require('controllers/main/service/info/configs');
+require('controllers/main/service/info/audit');
+require('controllers/main/service/add_controller');
+require('controllers/main/service/reassign_controller');
+require('controllers/main/service/reassign/step1_controller');
+require('controllers/main/service/reassign/step2_controller');
+require('controllers/main/service/reassign/step3_controller');
+require('controllers/main/service/reassign/step4_controller');
+require('controllers/main/service/reassign/step5_controller');
+require('controllers/main/service/reassign/step6_controller');
+require('controllers/main/service/manage_config_groups_controller');
+require('controllers/main/service/widgets/create/wizard_controller');
+require('controllers/main/service/widgets/create/step1_controller');
+require('controllers/main/service/widgets/create/step2_controller');
+require('controllers/main/service/widgets/create/step3_controller');
+require('controllers/main/service/widgets/edit_controller');
+require('controllers/main/host');
+require('controllers/main/host/bulk_operations_controller');
+require('controllers/main/host/details');
+require('controllers/main/host/configs_service');
+require('controllers/main/host/add_controller');
+require('controllers/main/host/combo_search_box');
+require('controllers/main/host/addHost/step4_controller');
+require('controllers/main/host/host_alerts_controller');
+require('controllers/main/charts');
+require('controllers/main/charts/heatmap_metrics/heatmap_metric');
+require('controllers/main/charts/heatmap');
+require('controllers/main/service/info/heatmap');
+require('controllers/main/views_controller');
+require('controllers/main/views/details_controller');
+require('controllers/wizard/step0_controller');
+require('controllers/wizard/step1_controller');
+require('controllers/wizard/step2_controller');
+require('controllers/wizard/step3_controller');
+require('controllers/wizard/step4_controller');
+require('controllers/wizard/step5_controller');
+require('controllers/wizard/step6_controller');
+require('controllers/wizard/step7_controller');
+require('controllers/wizard/step7/assign_master_controller');
+require('controllers/wizard/step7/pre_install_checks_controller');
+require('controllers/wizard/step8_controller');
+require('controllers/wizard/step9_controller');
+require('controllers/wizard/step10_controller');
+require('controllers/global/cluster_controller');
+require('controllers/global/update_controller');
+require('controllers/global/configuration_controller');
+require('controllers/main/service/reassign/step7_controller');
+
+});
+
+require.register("controllers/application", function(exports, require, module) {
+/**
+ * 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 = require('app');
+
+App.ApplicationController = Em.Controller.extend(App.UserPref, {
+
+  name: 'applicationController',
+
+  isPollerRunning: false,
+
+  clusterName: function () {
+    return (App.router.get('clusterController.clusterName') || 'My Cluster');
+  }.property('App.router.clusterController.clusterName'),
+
+  /**
+   * set ambari server version from installerController or mainController, making sure version shown up all the time
+   */
+  ambariVersion: function () {
+    return (App.router.get('installerController.ambariServerVersion') || App.router.get('mainController.ambariServerVersion') || Em.I18n.t('common.notAvailable'));
+  }.property('App.router.installerController.ambariServerVersion', 'App.router.mainController.ambariServerVersion'),
+
+  clusterDisplayName: Em.computed.truncate('clusterName', 13, 10),
+
+  isClusterDataLoaded: Em.computed.and('App.router.clusterController.isLoaded','App.router.loggedIn'),
+
+  isExistingClusterDataLoaded: Em.computed.and('App.router.clusterInstallCompleted', 'isClusterDataLoaded'),
+
+  enableLinks: Em.computed.and('isExistingClusterDataLoaded', '!App.isOnlyViewUser'),
+
+  /**
+   * Determines if "Exit" menu-item should be shown
+   * It should if cluster isn't installed
+   * If cluster is installer, <code>isClusterDataLoaded</code> is checked
+   * @type {boolean}
+   */
+  showExitLink: function () {
+    if (App.router.get('clusterInstallCompleted')) {
+      return this.get('isClusterDataLoaded');
+    }
+    return true;
+  }.property('App.router.clusterInstallCompleted', 'isClusterDataLoaded'),
+
+  init: function(){
+    this._super();
+  },
+
+  startKeepAlivePoller: function() {
+    if (!this.get('isPollerRunning')) {
+     this.set('isPollerRunning',true);
+      App.updater.run(this, 'getStack', 'isPollerRunning', App.sessionKeepAliveInterval);
+    }
+  },
+
+  getStack: function(callback) {
+    App.ajax.send({
+      name: 'router.login.clusters',
+      sender: this,
+      callback: callback
+    });
+  },
+
+  goToAdminView: function () {
+    App.router.route("adminView");
+  },
+
+  showAboutPopup: function() {
+
+    var self = this;
+    App.ModalPopup.show({
+      header: Em.I18n.t('common.aboutAmbari'),
+      secondary: false,
+      bodyClass: Em.View.extend({
+        templateName: require('templates/common/about'),
+        ambariVersion: this.get('ambariVersion')
+      })
+    });    
+  }
+
+});
+});
+
+require.register("controllers/experimental", function(exports, require, module) {
+/**
+ * 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 = require('app');
+
+App.ExperimentalController = Em.Controller.extend(App.UserPref, {
+  name: 'experimentalController',
+  supports: function () {
+    return Em.keys(App.get('supports')).map(function (sup) {
+      return Ember.Object.create({
+        name: sup,
+        selected: App.get('supports')[sup]
+      });
+    });
+  }.property('App.supports'),
+
+
+  loadSupports: function () {
+    return this.getUserPref('user-pref-' + App.router.get('loginName') + '-supports');
+  },
+
+  getUserPrefSuccessCallback: function (response, request, data) {
+    if (response) {
+      App.set('supports', response);
+    }
+  },
+
+  doSave: function () {
+    var supports = this.get('supports');
+    supports.forEach(function(s){
+      var propName = 'App.supports.' + s.get('name');
+      var propValue = s.get('selected');
+      Ember.set(propName, propValue);
+    });
+    this.postUserPref('user-pref-' + App.router.get('loginName') + '-supports', App.get('supports')).complete(function(){
+      App.router.transitionTo('root.index');
+    });
+  },
+
+  doCancel: function () {
+    App.router.transitionTo('root.index');
+  },
+
+  doResetUIStates: function () {
+    var self = this;
+    return App.ModalPopup.show({
+      header: Em.I18n.t('reset.ui.states'),
+      bodyClass: Ember.View.extend({
+        template: Ember.Handlebars.compile(Em.I18n.t('reset.ui.states.body'))
+      }),
+      primary: Em.I18n.t('yes'),
+      onPrimary: function () {
+        var router = App.router;
+        App.db.cleanUp();
+        router.clearAllSteps();
+        App.cache.clear();
+        App.clusterStatus.setClusterStatus({});
+        this.hide();
+        router.transitionTo('root.index');
+      }
+    });
+  }
+});
+
+});
+
+require.register("controllers/global/background_operations_controller", function(exports, require, module) {
+/**
+ * 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 = require('app');
+
+App.BackgroundOperationsController = Em.Controller.extend({
+  name: 'backgroundOperationsController',
+
+  /**
+   * Whether we need to refresh background operations or not
+   */
+  isWorking : false,
+
+  allOperationsCount : 0,
+
+  /**
+   * For host component popup
+   */
+  services:[],
+  serviceTimestamp: null,
+
+  /**
+   * Number of operation to load
+   */
+  operationsCount: 10,
+  /**
+   * Possible levels:
+   * REQUESTS_LIST
+   * HOSTS_LIST
+   * TASKS_LIST
+   * TASK_DETAILS
+   */
+  levelInfo: Em.Object.create({
+    name: 'REQUESTS_LIST',
+    requestId: null,
+    taskId: null
+  }),
+
+  /**
+   * Start polling, when <code>isWorking</code> become true
+   */
+  startPolling: function(){
+    if(this.get('isWorking')){
+      this.requestMostRecent();
+      App.updater.run(this, 'requestMostRecent', 'isWorking', App.bgOperationsUpdateInterval);
+    }
+  }.observes('isWorking'),
+
+  /**
+   * Get requests data from server
+   * @param callback
+   */
+  requestMostRecent: function (callback) {
+    var queryParams = this.getQueryParams();
+    App.ajax.send({
+      'name': queryParams.name,
+      'sender': this,
+      'success': queryParams.successCallback,
+      'callback': callback,
+      'data': queryParams.data
+    });
+    return !this.isInitLoading();
+  },
+
+  /**
+   * indicate whether data for current level has already been loaded or not
+   * @return {Boolean}
+   */
+  isInitLoading: function () {
+    var levelInfo = this.get('levelInfo');
+    var request = this.get('services').findProperty('id', levelInfo.get('requestId'));
+
+    if (levelInfo.get('name') === 'HOSTS_LIST') {
+      return !!(request && App.isEmptyObject(request.get('hostsMap')));
+    }
+    return false;
+  },
+  /**
+   * construct params of ajax query regarding displayed level
+   */
+  getQueryParams: function () {
+    var levelInfo = this.get('levelInfo');
+    var count = this.get('operationsCount');
+    var result = {
+      name: 'background_operations.get_most_recent',
+      successCallback: 'callBackForMostRecent',
+      data: {
+        'operationsCount': count
+      }
+    };
+    if (levelInfo.get('name') === 'TASK_DETAILS' && !App.get('testMode')) {
+      result.name = 'background_operations.get_by_task';
+      result.successCallback = 'callBackFilteredByTask';
+      result.data = {
+        'taskId': levelInfo.get('taskId'),
+        'requestId': levelInfo.get('requestId')
+      };
+    } else if (levelInfo.get('name') === 'TASKS_LIST' || levelInfo.get('name') === 'HOSTS_LIST') {
+      result.name = 'background_operations.get_by_request';
+      result.successCallback = 'callBackFilteredByRequest';
+      result.data = {
+        'requestId': levelInfo.get('requestId')
+      };
+    }
+    return result;
+  },
+
+  /**
+   * Push hosts and their tasks to request
+   * @param data
+   * @param ajaxQuery
+   * @param params
+   */
+  callBackFilteredByRequest: function (data, ajaxQuery, params) {
+    var requestId = data.Requests.id;
+    var requestInputs = data.Requests.inputs;
+    var request = this.get('services').findProperty('id', requestId);
+    var hostsMap = {};
+    var previousTaskStatusMap = request.get('previousTaskStatusMap');
+    var currentTaskStatusMap = {};
+    data.tasks.forEach(function (task) {
+      var host = hostsMap[task.Tasks.host_name];
+      task.Tasks.request_id = requestId;
+      task.Tasks.request_inputs = requestInputs;
+      if (host) {
+        host.logTasks.push(task);
+        host.isModified = (host.isModified) ? true : previousTaskStatusMap[task.Tasks.id] !== task.Tasks.status;
+      } else {
+        hostsMap[task.Tasks.host_name] = {
+          name: task.Tasks.host_name,
+          publicName: task.Tasks.host_name,
+          logTasks: [task],
+          isModified: previousTaskStatusMap[task.Tasks.id] !== task.Tasks.status
+        };
+      }
+      currentTaskStatusMap[task.Tasks.id] = task.Tasks.status;
+    }, this);
+    /**
+     * sync up request progress with up to date progress of hosts on Host's list,
+     * to avoid discrepancies while waiting for response with latest progress of request
+     * after switching to operation's list
+     */
+    if (request.get('isRunning')) {
+      request.set('progress', App.HostPopup.getProgress(data.tasks));
+      request.set('status', App.HostPopup.getStatus(data.tasks)[0]);
+      request.set('isRunning', request.get('progress') !== 100);
+    }
+    request.set('previousTaskStatusMap', currentTaskStatusMap);
+    request.set('hostsMap', hostsMap);
+    this.set('serviceTimestamp', App.dateTime());
+  },
+  /**
+   * Update task, with uploading two additional properties: stdout and stderr
+   * @param data
+   * @param ajaxQuery
+   * @param params
+   */
+  callBackFilteredByTask: function (data, ajaxQuery, params) {
+    var request = this.get('services').findProperty('id', data.Tasks.request_id);
+    var host = request.get('hostsMap')[data.Tasks.host_name];
+    var task = host.logTasks.findProperty('Tasks.id', data.Tasks.id);
+    task.Tasks.status = data.Tasks.status;
+    task.Tasks.stdout = data.Tasks.stdout;
+    task.Tasks.stderr = data.Tasks.stderr;
+
+    // Put some command information to task object
+    task.Tasks.command = data.Tasks.command;
+    task.Tasks.custom_command_name = data.Tasks.custom_command_name;
+    task.Tasks.structured_out = data.Tasks.structured_out;
+
+    task.Tasks.output_log = data.Tasks.output_log;
+    task.Tasks.error_log = data.Tasks.error_log;
+    this.set('serviceTimestamp', App.dateTime());
+  },
+
+  /**
+   * returns true if it's upgrade equest
+   * use this flag to exclude upgrade requests from bgo
+   * @param {object} request
+   * @returns {boolean}
+   */
+  isUpgradeRequest: function(request) {
+    var context = Em.get(request, 'Requests.request_context');
+    return context ? /(upgrading|downgrading)/.test(context.toLowerCase()) : false;
+  },
+  /**
+   * Prepare, received from server, requests for host component popup
+   * @param data
+   */
+  callBackForMostRecent: function (data) {
+    var runningServices = 0;
+    var currentRequestIds = [];
+    var countIssued = this.get('operationsCount');
+    var countGot = data.itemTotal;
+    var restoreUpgradeState = false;
+
+    data.items.forEach(function (request) {
+      if (this.isUpgradeRequest(request)) {
+        if (!App.get('upgradeIsRunning') && !App.get('testMode')) {
+          restoreUpgradeState = true;
+        }
+        return;
+      }
+      var rq = this.get("services").findProperty('id', request.Requests.id);
+      var isRunning = this.isRequestRunning(request);
+      var requestParams = this.parseRequestContext(request.Requests.request_context);
+      this.assignScheduleId(request, requestParams);
+      currentRequestIds.push(request.Requests.id);
+
+      if (rq) {
+        rq.setProperties({
+          progress: Math.floor(request.Requests.progress_percent),
+          status: request.Requests.request_status,
+          isRunning: isRunning,
+          startTime: App.dateTimeWithTimeZone(request.Requests.start_time),
+          endTime: request.Requests.end_time > 0 ? App.dateTimeWithTimeZone(request.Requests.end_time) : request.Requests.end_time
+        });
+      } else {
+        rq = Em.Object.create({
+          id: request.Requests.id,
+          name: requestParams.requestContext,
+          displayName: requestParams.requestContext,
+          progress: Math.floor(request.Requests.progress_percent),
+          status: request.Requests.request_status,
+          isRunning: isRunning,
+          hostsMap: {},
+          tasks: [],
+          startTime: App.dateTimeWithTimeZone(request.Requests.start_time),
+          endTime: request.Requests.end_time > 0 ? App.dateTimeWithTimeZone(request.Requests.end_time) : request.Requests.end_time,
+          dependentService: requestParams.dependentService,
+          sourceRequestScheduleId: request.Requests.request_schedule && request.Requests.request_schedule.schedule_id,
+          previousTaskStatusMap: {},
+          contextCommand: requestParams.contextCommand
+        });
+        this.get("services").unshift(rq);
+        //To sort DESC by request id
+        this.set("services", this.get("services").sortProperty('id').reverse());
+      }
+      runningServices += ~~isRunning;
+    }, this);
+    if (restoreUpgradeState) {
+      App.router.get('clusterController').restoreUpgradeState();
+    }
+    this.removeOldRequests(currentRequestIds);
+    this.set("allOperationsCount", runningServices);
+    this.set('isShowMoreAvailable', countGot >= countIssued);
+    this.set('serviceTimestamp', App.dateTimeWithTimeZone());
+  },
+
+  isShowMoreAvailable: null,
+
+  /**
+   * remove old requests
+   * as API returns 10, or  20 , or 30 ...etc latest request, the requests that absent in response should be removed
+   * @param currentRequestIds
+   */
+  removeOldRequests: function (currentRequestIds) {
+    var services = this.get('services');
+
+    for (var i = 0, l = services.length; i < l; i++) {
+      if (!currentRequestIds.contains(services[i].id)) {
+        services.splice(i, 1);
+        i--;
+        l--;
+      }
+    }
+  },
+
+  /**
+   * identify whether request is running by task counters
+   * @param request
+   * @return {Boolean}
+   */
+  isRequestRunning: function (request) {
+    return (request.Requests.task_count -
+      (request.Requests.aborted_task_count + request.Requests.completed_task_count + request.Requests.failed_task_count
+        + request.Requests.timed_out_task_count - request.Requests.queued_task_count)) > 0;
+  },
+  /**
+   * identify whether there is only one host in request
+   * @param inputs
+   * @return {Boolean}
+   */
+  isOneHost: function (inputs) {
+    if (!inputs) {
+      return false;
+    }
+    inputs = JSON.parse(inputs);
+    if (inputs && inputs.included_hosts) {
+      return inputs.included_hosts.split(',').length < 2;
+    }
+    return false
+  },
+  /**
+   * assign schedule_id of request to null if it's Recommission operation
+   * @param request
+   * @param requestParams
+   */
+  assignScheduleId: function (request, requestParams) {
+    var oneHost = this.isOneHost(request.Requests.inputs);
+    if (request.Requests.request_schedule && oneHost && /Recommission/.test(requestParams.requestContext)) {
+      request.Requests.request_schedule.schedule_id = null;
+    }
+  },
+
+  /**
+   * parse request context and if keyword "_PARSE_" is present then format it
+   * @param requestContext
+   * @return {Object}
+   */
+  parseRequestContext: function (requestContext) {
+    var parsedRequestContext;
+    var service;
+    var contextCommand;
+    if (requestContext) {
+      if (requestContext.indexOf(App.BackgroundOperationsController.CommandContexts.PREFIX) !== -1) {
+        var contextSplits = requestContext.split('.');
+        contextCommand = contextSplits[1];
+        service = contextSplits[2];
+        switch(contextCommand){
+        case "STOP":
+        case "START":
+          if (service === 'ALL_SERVICES') {
+            parsedRequestContext = Em.I18n.t("requestInfo." + contextCommand.toLowerCase()).format(Em.I18n.t('common.allServices'));
+          } else {
+            parsedRequestContext = Em.I18n.t("requestInfo." + contextCommand.toLowerCase()).format(App.format.role(service, true));
+          }
+          break;
+        case "ROLLING-RESTART":
+          parsedRequestContext = Em.I18n.t("rollingrestart.rest.context").format(App.format.role(service, true), contextSplits[3], contextSplits[4]);
+          break;
+        }
+      } else {
+        parsedRequestContext = requestContext;
+      }
+    } else {
+      parsedRequestContext = Em.I18n.t('requestInfo.unspecified');
+    }
+    return {
+      requestContext: parsedRequestContext,
+      dependentService: service,
+      contextCommand: contextCommand
+    }
+  },
+
+  popupView: null,
+
+  /**
+   * Onclick handler for background operations number located right to logo
+   */
+  showPopup: function(){
+    // load the checkbox on footer first, then show popup.
+    var self = this;
+    App.router.get('userSettingsController').dataLoading('show_bg').done(function (initValue) {
+      App.updater.immediateRun('requestMostRecent');
+      if(self.get('popupView') && App.HostPopup.get('isBackgroundOperations')){
+        self.set ('popupView.isNotShowBgChecked', !initValue);
+        self.set('popupView.isOpen', true);
+        $(self.get('popupView.element')).appendTo('#wrapper');
+      } else {
+        self.set('popupView', App.HostPopup.initPopup("", self, true));
+        self.set('popupView.isNotShowBgChecked', !initValue);
+      }
+    });
+  },
+
+  /**
+   * Called on logout
+   */
+  clear: function () {
+    // set operations count to default value
+    this.set('operationsCount', 10);
+  }
+
+});
+
+/**
+ * Each background operation has a context in which it operates.
+ * Generally these contexts are fixed messages. However, we might
+ * want to associate semantics to this context - like showing, disabling
+ * buttons when certain operations are in progress.
+ *
+ * To make this possible we have command contexts where the context
+ * is not a human readable string, but a pattern indicating the command
+ * it is running. When UI shows these, they are translated into human
+ * readable strings.
+ *
+ * General pattern of context names is "_PARSE_.{COMMAND}.{ID}[.{Additional-Data}...]"
+ */
+App.BackgroundOperationsController.CommandContexts = {
+  PREFIX : "_PARSE_",
+  /**
+   * Stops all services
+   */
+  STOP_ALL_SERVICES : "_PARSE_.STOP.ALL_SERVICES",
+  /**
+   * Starts all services
+   */
+  START_ALL_SERVICES : "_PARSE_.START.ALL_SERVICES",
+  /**
+   * Starts service indicated by serviceID.
+   * @param {String} serviceID Parameter {0}. Example: HDFS
+   */
+  START_SERVICE : "_PARSE_.START.{0}",
+  /**
+   * Stops service indicated by serviceID.
+   * @param {String} serviceID Parameter {0}. Example: HDFS
+   */
+  STOP_SERVICE : "_PARSE_.STOP.{0}",
+  /**
+   * Performs rolling restart of componentID in batches.
+   * This context is the batchNumber batch out of totalBatchCount batches.
+   * @param {String} componentID Parameter {0}. Example "DATANODE"
+   * @param {Number} batchNumber Parameter {1}. Batch number of this batch. Example 3.
+   * @param {Number} totalBatchCount Parameter {2}. Total number of batches. Example 10.
+   */
+  ROLLING_RESTART : "_PARSE_.ROLLING-RESTART.{0}.{1}.{2}"
+};
+
+});
+
+require.register("controllers/global/cluster_controller", function(exports, require, module) {
+/**
+ * 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 = require('app');
+var stringUtils = require('utils/string_utils');
+var credentialUtils = require('utils/credentials');
+
+App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
+  name: 'clusterController',
+  isLoaded: false,
+  ambariProperties: null,
+  clusterEnv: null,
+  clusterDataLoadedPercent: 'width:0', // 0 to 1
+
+  isClusterNameLoaded: false,
+
+  isAlertsLoaded: false,
+
+  isComponentsStateLoaded: false,
+
+  isHostsLoaded: false,
+
+  isConfigsPropertiesLoaded: false,
+
+  isComponentsConfigLoaded: false,
+
+  isStackConfigsLoaded: false,
+
+  isServiceMetricsLoaded: false,
+
+  /**
+   * @type {boolean}
+   */
+  isHostComponentMetricsLoaded: false,
+
+  /**
+   * Ambari uses custom jdk.
+   * @type {Boolean}
+   */
+  isCustomJDK: false,
+
+  isHostContentLoaded: Em.computed.and('isHostsLoaded', 'isComponentsStateLoaded'),
+
+  isServiceContentFullyLoaded: Em.computed.and('isServiceMetricsLoaded', 'isComponentsStateLoaded', 'isComponentsConfigLoaded'),
+
+  clusterName: Em.computed.alias('App.clusterName'),
+
+  updateLoadStatus: function (item) {
+    var loadList = this.get('dataLoadList');
+    var loaded = true;
+    var numLoaded = 0;
+    var loadListLength = 0;
+    loadList.set(item, true);
+    for (var i in loadList) {
+      if (loadList.hasOwnProperty(i)) {
+        loadListLength++;
+        if (!loadList[i] && loaded) {
+          loaded = false;
+        }
+      }
+      // calculate the number of true
+      if (loadList.hasOwnProperty(i) && loadList[i]) {
+        numLoaded++;
+      }
+    }
+    this.set('isLoaded', loaded);
+    this.set('clusterDataLoadedPercent', 'width:' + (Math.floor(numLoaded / loadListLength * 100)).toString() + '%');
+  },
+
+  dataLoadList: Em.Object.create({
+    'stackComponents': false,
+    'services': false
+  }),
+
+  /**
+   * load cluster name
+   */
+  loadClusterName: function (reload, deferred) {
+    var dfd = deferred || $.Deferred();
+
+    if (App.get('clusterName') && !reload) {
+      App.set('clusterName', this.get('clusterName'));
+      this.set('isClusterNameLoaded', true);
+      dfd.resolve();
+    } else {
+      App.ajax.send({
+        name: 'cluster.load_cluster_name',
+        sender: this,
+        data: {
+          reloadPopupText: Em.I18n.t('app.reloadPopup.noClusterName.text'),
+          errorLogMessage: 'failed on loading cluster name',
+          callback: this.loadClusterName,
+          args: [reload, dfd],
+          shouldUseDefaultHandler: true
+        },
+        success: 'reloadSuccessCallback',
+        error: 'reloadErrorCallback',
+        callback: function () {
+          if (!App.get('currentStackVersion')) {
+            App.set('currentStackVersion', App.defaultStackVersion);
+          }
+        }
+      }).then(
+        function () {
+          dfd.resolve();
+        },
+        null
+      );
+    }
+    return dfd.promise();
+  },
+
+  reloadSuccessCallback: function (data) {
+    this._super();
+    if (data.items && data.items.length > 0) {
+      App.setProperties({
+        clusterName: data.items[0].Clusters.cluster_name,
+        currentStackVersion: data.items[0].Clusters.version,
+        isKerberosEnabled: data.items[0].Clusters.security_type === 'KERBEROS'
+      });
+      this.set('isClusterNameLoaded', true);
+    }
+  },
+
+  /**
+   * load current server clock in milli-seconds
+   */
+  loadClientServerClockDistance: function () {
+    var dfd = $.Deferred();
+    this.getServerClock().done(function () {
+      dfd.resolve();
+    });
+    return dfd.promise();
+  },
+
+  getServerClock: function () {
+    return App.ajax.send({
+      name: 'ambari.service',
+      sender: this,
+      data: {
+        fields: '?fields=RootServiceComponents/server_clock'
+      },
+      success: 'getServerClockSuccessCallback',
+      error: 'getServerClockErrorCallback'
+    });
+  },
+  getServerClockSuccessCallback: function (data) {
+    var clientClock = new Date().getTime();
+    var serverClock = (data.RootServiceComponents.server_clock).toString();
+    serverClock = serverClock.length < 13 ? serverClock + '000' : serverClock;
+    App.set('clockDistance', serverClock - clientClock);
+    App.set('currentServerTime', parseInt(serverClock));
+  },
+  getServerClockErrorCallback: function () {
+  },
+
+  getUrl: function (testUrl, url) {
+    return (App.get('testMode')) ? testUrl : App.get('apiPrefix') + '/clusters/' + App.get('clusterName') + url;
+  },
+
+  /**
+   *  load all data and update load status
+   */
+  loadClusterData: function () {
+    var self = this;
+    this.loadAuthorizations();
+    this.getAllHostNames();
+    this.loadAmbariProperties();
+    if (!App.get('clusterName')) {
+      return;
+    }
+
+    if (this.get('isLoaded')) { // do not load data repeatedly
+      App.router.get('mainController').startPolling();
+      return;
+    }
+    App.router.get('userSettingsController').getAllUserSettings();
+    var clusterUrl = this.getUrl('/data/clusters/cluster.json', '?fields=Clusters');
+    var hostsController = App.router.get('mainHostController');
+    hostsController.set('isCountersUpdating', true);
+    hostsController.updateStatusCounters();
+
+    App.HttpClient.get(clusterUrl, App.clusterMapper, {
+      complete: function (jqXHR, textStatus) {
+        App.set('isCredentialStorePersistent', Em.getWithDefault(App.Cluster.find().findProperty('clusterName', App.get('clusterName')), 'isCredentialStorePersistent', false));
+      }
+    }, function (jqXHR, textStatus) {
+    });
+
+
+    self.restoreUpgradeState();
+
+    App.router.get('wizardWatcherController').getUser();
+
+    var updater = App.router.get('updateController');
+
+    /**
+     * Order of loading:
+     * 1. load all created service components
+     * 2. request for service components supported by stack
+     * 3. load stack components to model
+     * 4. request for services
+     * 5. put services in cache
+     * 6. request for hosts and host-components (single call)
+     * 7. request for service metrics
+     * 8. load host-components to model
+     * 9. load services from cache with metrics to model
+     */
+    self.loadStackServiceComponents(function (data) {
+      data.items.forEach(function (service) {
+        service.StackServices.is_selected = true;
+        service.StackServices.is_installed = false;
+      }, self);
+      App.stackServiceMapper.mapStackServices(data);
+      App.config.setPreDefinedServiceConfigs(true);
+      self.updateLoadStatus('stackComponents');
+      updater.updateServices(function () {
+        self.updateLoadStatus('services');
+
+        //hosts should be loaded after services in order to properly populate host-component relation in App.cache.services
+        updater.updateHost(function () {
+          self.set('isHostsLoaded', true);
+        });
+        App.config.loadConfigsFromStack(App.Service.find().mapProperty('serviceName')).complete(function () {
+          App.config.loadClusterConfigsFromStack().complete(function () {
+            self.set('isConfigsPropertiesLoaded', true);
+          });
+        });
+        // components state loading doesn't affect overall progress
+        updater.updateComponentsState(function () {
+          self.set('isComponentsStateLoaded', true);
+          // service metrics should be loaded after components state for mapping service components to service in the DS model
+          // service metrics loading doesn't affect overall progress
+          updater.updateServiceMetric(function () {
+            self.set('isServiceMetricsLoaded', true);
+            // make second call, because first is light since it doesn't request host-component metrics
+            updater.updateServiceMetric(function() {
+              self.set('isHostComponentMetricsLoaded', true);
+            });
+            // components config loading doesn't affect overall progress
+            updater.updateComponentConfig(function () {
+              self.set('isComponentsConfigLoaded', true);
+            });
+          });
+        });
+      });
+    });
+
+    //force clear filters  for hosts page to load all data
+    App.db.setFilterConditions('mainHostController', null);
+
+    // alerts loading doesn't affect overall progress
+    console.time('Overall alerts loading time');
+    updater.updateAlertGroups(function () {
+      updater.updateAlertDefinitions(function () {
+        updater.updateAlertDefinitionSummary(function () {
+          updater.updateUnhealthyAlertInstances(function () {
+            console.timeEnd('Overall alerts loading time');
+            self.set('isAlertsLoaded', true);
+          });
+        });
+      });
+    });
+
+    //load cluster-env, used by alert check tolerance // TODO services auto-start
+    updater.updateClusterEnv();
+
+    /*  Root service mapper maps all the data exposed under Ambari root service which includes ambari configurations i.e ambari-properties
+     ** This is useful information but its not being used in the code anywhere as of now
+
+     self.loadRootService().done(function (data) {
+     App.rootServiceMapper.map(data);
+     self.updateLoadStatus('rootService');
+     });
+
+     */
+  },
+
+  /**
+   * restore upgrade status from server
+   * and make call to get latest status from server
+   */
+  restoreUpgradeState: function () {
+    return this.getAllUpgrades().done(function (data) {
+      var upgradeController = App.router.get('mainAdminStackAndUpgradeController');
+      var lastUpgradeData = data.items.sortProperty('Upgrade.request_id').pop();
+      var dbUpgradeState = App.db.get('MainAdminStackAndUpgrade', 'upgradeState');
+
+      if (!Em.isNone(dbUpgradeState)) {
+        App.set('upgradeState', dbUpgradeState);
+      }
+
+      if (lastUpgradeData) {
+        upgradeController.restoreLastUpgrade(lastUpgradeData);
+      } else {
+        upgradeController.initDBProperties();
+        upgradeController.loadUpgradeData(true);
+      }
+      upgradeController.loadStackVersionsToModel(true).done(function () {
+        App.set('stackVersionsAvailable', App.StackVersion.find().content.length > 0);
+      });
+    });
+  },
+
+  loadRootService: function () {
+    return App.ajax.send({
+      name: 'service.ambari',
+      sender: this
+    });
+  },
+
+  requestHosts: function (realUrl, callback) {
+    var testHostUrl = '/data/hosts/HDP2/hosts.json';
+    var url = this.getUrl(testHostUrl, realUrl);
+    App.HttpClient.get(url, App.hostsMapper, {
+      complete: callback
+    }, callback)
+  },
+
+  /**
+   *
+   * @param callback
+   */
+  loadStackServiceComponents: function (callback) {
+    var callbackObj = {
+      loadStackServiceComponentsSuccess: callback
+    };
+    App.ajax.send({
+      name: 'wizard.service_components',
+      data: {
+        stackUrl: App.get('stackVersionURL'),
+        stackVersion: App.get('currentStackVersionNumber')
+      },
+      sender: callbackObj,
+      success: 'loadStackServiceComponentsSuccess'
+    });
+  },
+
+  loadAmbariProperties: function () {
+    return App.ajax.send({
+      name: 'ambari.service',
+      sender: this,
+      success: 'loadAmbariPropertiesSuccess',
+      error: 'loadAmbariPropertiesError'
+    });
+  },
+
+  loadAuthorizations: function() {
+    return App.ajax.send({
+      name: 'router.user.authorizations',
+      sender: this,
+      data: {userName: App.db.getLoginName()},
+      success: 'loadAuthorizationsSuccessCallback'
+    });
+  },
+
+  loadAuthorizationsSuccessCallback: function(response) {
+    if (response && response.items) {
+      App.set('auth', response.items.mapProperty('AuthorizationInfo.authorization_id').uniq());
+      App.db.setAuth(App.get('auth'));
+    }
+  },
+
+  loadAmbariPropertiesSuccess: function (data) {
+    this.set('ambariProperties', data.RootServiceComponents.properties);
+    // Absence of 'jdk.name' and 'jce.name' properties says that ambari configured with custom jdk.
+    this.set('isCustomJDK', App.isEmptyObject(App.permit(data.RootServiceComponents.properties, ['jdk.name', 'jce.name'])));
+    App.router.get('mainController').monitorInactivity();
+  },
+
+  loadAmbariPropertiesError: function () {
+
+  },
+
+  updateClusterData: function () {
+    var testUrl = '/data/clusters/HDP2/cluster.json';
+    var clusterUrl = this.getUrl(testUrl, '?fields=Clusters');
+    App.HttpClient.get(clusterUrl, App.clusterMapper, {
+      complete: function () {
+      }
+    });
+  },
+
+  /**
+   *
+   * @returns {*|Transport|$.ajax|boolean|ServerResponse}
+   */
+  getAllHostNames: function () {
+    return App.ajax.send({
+      name: 'hosts.all',
+      sender: this,
+      success: 'getHostNamesSuccess',
+      error: 'getHostNamesError'
+    });
+  },
+
+  getHostNamesSuccess: function (data) {
+    App.set("allHostNames", data.items.mapProperty("Hosts.host_name"));
+  },
+
+  getHostNamesError: function () {
+
+  },
+
+
+  /**
+   * puts kerberos admin credentials in the live cluster session
+   * and resend ajax request
+   * @param {credentialResourceObject} credentialResource
+   * @param {object} ajaxOpt
+   * @returns {$.ajax}
+   */
+  createKerberosAdminSession: function (credentialResource, ajaxOpt) {
+    return credentialUtils.createOrUpdateCredentials(App.get('clusterName'), credentialUtils.ALIAS.KDC_CREDENTIALS, credentialResource).then(function() {
+      if (ajaxOpt) {
+        $.ajax(ajaxOpt);
+      }
+    });
+  },
+
+  //TODO Replace this check with any other which is applicable to non-HDP stack
+  /**
+   * Check if HDP stack version is more or equal than 2.2.2 to determine if pluggable metrics for Storm are supported
+   * @method checkDetailedRepoVersion
+   * @returns {promise|*|promise|promise|HTMLElement|promise}
+   */
+  checkDetailedRepoVersion: function () {
+    var dfd;
+    var currentStackName = App.get('currentStackName');
+    var currentStackVersionNumber = App.get('currentStackVersionNumber');
+    if (currentStackName == 'HDP' && currentStackVersionNumber == '2.2') {
+      dfd = App.ajax.send({
+        name: 'cluster.load_detailed_repo_version',
+        sender: this,
+        success: 'checkDetailedRepoVersionSuccessCallback',
+        error: 'checkDetailedRepoVersionErrorCallback'
+      });
+    } else {
+      dfd = $.Deferred();
+      App.set('isStormMetricsSupported', currentStackName != 'HDP' || stringUtils.compareVersions(currentStackVersionNumber, '2.2') == 1);
+      dfd.resolve();
+    }
+    return dfd.promise();
+  },
+
+  checkDetailedRepoVersionSuccessCallback: function (data) {
+    var items = data.items;
+    var version;
+    if (items && items.length) {
+      var repoVersions = items[0].repository_versions;
+      if (repoVersions && repoVersions.length) {
+        version = Em.get(repoVersions[0], 'RepositoryVersions.repository_version');
+      }
+    }
+    App.set('isStormMetricsSupported', stringUtils.compareVersions(version, '2.2.2') > -1 || !version);
+  },
+  checkDetailedRepoVersionErrorCallback: function () {
+    App.set('isStormMetricsSupported', true);
+  },
+
+  /**
+   * Load required data for all upgrades from API
+   * @returns {$.ajax}
+   */
+  getAllUpgrades: function () {
+    return App.ajax.send({
+      name: 'cluster.load_last_upgrade',
+      sender: this
+    });
+  }
+});
+
+});
+
+require.register("controllers/global/configuration_controller", function(exports, require, module) {
+/**
+ * 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 = require('app');
+
+App.ConfigurationController = Em.Controller.extend({
+  name: 'configurationController',
+
+  /**
+   * get configs by tags
+   * return Deferred object with configs as argument
+   * @param tags {Object}
+   * ** siteName
+   * ** tagName (optional)
+   * @return {object}
+   */
+  getConfigsByTags: function (tags) {
+    var storedTags = [];
+    App.db.getConfigs().forEach(function (site) {
+      storedTags.push({
+        siteName: site.type,
+        tagName: site.tag
+      })
+    });
+    if (this.checkTagsChanges(tags, storedTags)) {
+      return this.loadFromServer(tags);
+    } else {
+      return this.loadFromDB(tags.mapProperty('siteName'));
+    }
+  },
+  /**
+   * check whether tag versions have been changed
+   * if they are different then return true
+   * otherwise false
+   * @param tags
+   * @param storedTags
+   * @return {Boolean}
+   */
+  checkTagsChanges: function (tags, storedTags) {
+    var isDifferent = false;
+    var i = 0;
+    while (i < tags.length && !isDifferent) {
+      var storedTag = storedTags.findProperty('siteName', tags[i].siteName);
+      isDifferent = (!storedTag || !tags[i].tagName || storedTag.tagName !== tags[i].tagName);
+      i++;
+    }
+    return isDifferent;
+  },
+  loadFromDB: function (siteNames) {
+    var dfd = $.Deferred();
+    var configs = App.db.getConfigs().filter(function (site) {
+      return (siteNames.contains(site.type));
+    });
+    dfd.resolve(configs);
+    return dfd.promise()
+  },
+  /**
+   * load configs from server
+   * and update them in local DB
+   * @param tags
+   * @return {Array}
+   */
+  loadFromServer: function (tags) {
+    var self = this;
+    var dfd = $.Deferred();
+    if (!tags.everyProperty('tagName')) {
+      var configTags;
+      var jqXhr =  this.loadConfigTags();
+      jqXhr.done(function (data) {
+        configTags = data.Clusters.desired_configs;
+        tags.forEach(function (_tag) {
+          if (_tag.siteName && configTags[_tag.siteName] && !_tag.tagName) {
+            _tag.tagName = configTags[_tag.siteName].tag;
+          }
+        }, self);
+        self.loadConfigsByTags(tags,dfd);
+      });
+    } else {
+      self.loadConfigsByTags(tags,dfd);
+    }
+    return dfd.promise();
+  },
+
+  /**
+   *  loadConfigsByTags: Loads properties for a config tag
+   *  @params tags
+   *  @params dfd jqXhr promise
+   */
+  loadConfigsByTags: function (tags,dfd) {
+    var self = this;
+    var loadedConfigs = [];
+    App.config.loadConfigsByTags(tags).done(function (data) {
+      if (data.items) {
+        data.items.forEach(function (item) {
+          loadedConfigs.push(item);
+        });
+      }
+    }).complete(function () {
+      self.saveToDB(loadedConfigs);
+      dfd.resolve(loadedConfigs);
+    });
+  },
+
+  /**
+   * loadConfigTags: Loads all config tags applied to the cluster
+   * @return: jqXhr promise
+   */
+  loadConfigTags: function () {
+    return App.ajax.send({
+      name: 'config.tags',
+      sender: this
+    });
+  },
+
+  /**
+   * save properties obtained from server to local DB
+   * @param loadedConfigs
+   */
+  saveToDB: function (loadedConfigs) {
+    var storedConfigs = App.db.getConfigs();
+    loadedConfigs.forEach(function (loadedSite) {
+      var storedSite = storedConfigs.findProperty('type', loadedSite.type);
+      if (storedSite) {
+        storedSite.tag = loadedSite.tag;
+        storedSite.properties = loadedSite.properties;
+        storedSite.properties_attributes = loadedSite.properties_attributes;
+      } else {
+        storedConfigs.push(loadedSite);
+      }
+    });
+    App.db.setConfigs(storedConfigs);
+  }
+});
+
+});
+
+require.register("controllers/global/errors_handler_controller", function(exports, require, module) {
+/**
+ * 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 = require('app');
+
+App.ErrorsHandlerController = Em.Controller.extend(App.UserPref, {
+  init: function () {
+    var oldError = window.onerror || Em.K;
+    var self = this;
+    window.onerror = function (err, url, lineNumber, colNumber, Err) {
+      oldError.call(this, err, url, lineNumber, colNumber, Err);
+      var ls = localStorage.getObject('errors') || {};
+      if(Object.keys(localStorage.getObject('errors')).length > 25) {
+        delete ls[Object.keys(ls).sort()[0]];
+      }
+      var key = new Date().getTime();
+      var val = {
+        file: url,
+        line: lineNumber,
+        col: colNumber,
+        error: err,
+        stackTrace: Em.get(Err || {}, 'stack')
+      };
+      ls[key] = val;
+      localStorage.setObject('errors', ls);
+      self.postUserPref(key, val);
+    };
+    return this._super();
+  }
+});
+
+});
+
+require.register("controllers/global/update_controller", function(exports, require, module) {
+/**
+ * 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 = require('app');
+
+App.UpdateController = Em.Controller.extend({
+  name: 'updateController',
+  isUpdated: false,
+  cluster: null,
+  isWorking: false,
+  updateAlertInstances: Em.computed.and('isWorking', '!App.router.mainAlertInstancesController.isUpdating'),
+  timeIntervalId: null,
+  clusterName: Em.computed.alias('App.router.clusterController.clusterName'),
+
+  /**
+   * keys which should be preloaded in order to filter hosts by host-components
+   */
+  hostsPreLoadKeys: ['host_components/HostRoles/component_name', 'host_components/HostRoles/stale_configs', 'host_components/HostRoles/maintenance_state'],
+
+  paginationKeys: ['page_size', 'from'],
+
+  /**
+   * @type {Array}
+   */
+  serviceComponentMetrics: [
+    'host_components/metrics/jvm/memHeapUsedM',
+    'host_components/metrics/jvm/HeapMemoryMax',
+    'host_components/metrics/jvm/HeapMemoryUsed',
+    'host_components/metrics/jvm/memHeapCommittedM',
+    'host_components/metrics/mapred/jobtracker/trackers_decommissioned',
+    'host_components/metrics/cpu/cpu_wio',
+    'host_components/metrics/rpc/client/RpcQueueTime_avg_time',
+    'host_components/metrics/dfs/FSNamesystem/*',
+    'host_components/metrics/dfs/namenode/Version',
+    'host_components/metrics/dfs/namenode/LiveNodes',
+    'host_components/metrics/dfs/namenode/DeadNodes',
+    'host_components/metrics/dfs/namenode/DecomNodes',
+    'host_components/metrics/dfs/namenode/TotalFiles',
+    'host_components/metrics/dfs/namenode/UpgradeFinalized',
+    'host_components/metrics/dfs/namenode/Safemode',
+    'host_components/metrics/runtime/StartTime'
+  ],
+
+  /**
+   * @type {object}
+   */
+  serviceSpecificParams: {
+    'FLUME': "host_components/processes/HostComponentProcess",
+    'YARN':  "host_components/metrics/yarn/Queue," +
+             "host_components/metrics/yarn/ClusterMetrics/NumActiveNMs," +
+             "host_components/metrics/yarn/ClusterMetrics/NumLostNMs," +
+             "host_components/metrics/yarn/ClusterMetrics/NumUnhealthyNMs," +
+             "host_components/metrics/yarn/ClusterMetrics/NumRebootedNMs," +
+             "host_components/metrics/yarn/ClusterMetrics/NumDecommissionedNMs",
+    'HBASE': "host_components/metrics/hbase/master/IsActiveMaster," +
+             "host_components/metrics/hbase/master/MasterStartTime," +
+             "host_components/metrics/hbase/master/MasterActiveTime," +
+             "host_components/metrics/hbase/master/AverageLoad," +
+             "host_components/metrics/master/AssignmentManger/ritCount",
+    'STORM': 'metrics/api/v1/cluster/summary,metrics/api/v1/topology/summary,metrics/api/v1/nimbus/summary'
+  },
+
+  /**
+   * @type {string}
+   */
+  HOSTS_TEST_URL: '/data/hosts/HDP2/hosts.json',
+
+  /**
+   * map which track status of requests, whether it's running or completed
+   * @type {object}
+   */
+  requestsRunningStatus: {
+    "updateServiceMetric": false
+  },
+
+  getUrl: function (testUrl, url) {
+    return App.get('testMode') ? testUrl : App.apiPrefix + '/clusters/' + this.get('clusterName') + url;
+  },
+
+  /**
+   * construct URL from real URL and query parameters
+   * @param realUrl
+   * @param queryParams
+   * @return {String}
+   */
+  getComplexUrl: function (realUrl, queryParams) {
+    var prefix = App.get('apiPrefix') + '/clusters/' + App.get('clusterName'),
+      params = '';
+
+    if (queryParams) {
+      params = this.computeParameters(queryParams);
+    }
+    params = params.length > 0 ? params + "&" : params;
+    return prefix + realUrl.replace('<parameters>', params);
+  },
+
+  /**
+   * compute parameters according to their type
+   * @param queryParams
+   * @return {String}
+   */
+  computeParameters: function (queryParams) {
+    var params = '';
+
+    queryParams.forEach(function (param) {
+      var customKey = param.key;
+
+      switch (param.type) {
+        case 'EQUAL':
+          if (Em.isArray(param.value)) {
+            params += param.key + '.in(' + param.value.join(',') + ')';
+          } else {
+            params += param.key + '=' + param.value;
+          }
+          break;
+        case 'LESS':
+          params += param.key + '<' + param.value;
+          break;
+        case 'MORE':
+          params += param.key + '>' + param.value;
+          break;
+        case 'MATCH':
+          if (Em.isArray(param.value)) {
+            params += '(' + param.value.map(function(v) {
+              return param.key + '.matches(' + v + ')';
+            }).join('|') + ')';
+          } else {
+            params += param.key + '.matches(' + param.value + ')';
+          }
+          break;
+        case 'MULTIPLE':
+          params += param.key + '.in(' + param.value.join(',') + ')';
+          break;
+        case 'SORT':
+          params += 'sortBy=' + param.key + '.' + param.value;
+          break;
+        case 'CUSTOM':
+          param.value.forEach(function (item, index) {
+            customKey = customKey.replace('{' + index + '}', item);
+          }, this);
+          params += customKey;
+          break;
+        case 'COMBO':
+          params += App.router.get('mainHostComboSearchBoxController').generateQueryParam(param);
+          break;
+      }
+      params += '&';
+    });
+    return params.substring(0, params.length - 1);
+  },
+
+  /**
+   * depict query parameters of table
+   */
+  queryParams: Em.Object.create({
+    'Hosts': []
+  }),
+
+  /**
+   * Pagination query-parameters for unhealthy alerts request
+   * @type {{from: Number, page_size: Number}}
+   */
+  queryParamsForUnhealthyAlertInstances: {
+    from: 0,
+    page_size: 10
+  },
+
+  /**
+   * map describes relations between updater function and table
+   */
+  tableUpdaterMap: {
+    'Hosts': 'updateHost'
+  },
+
+  /**
+   * Start polling, when <code>isWorking</code> become true
+   */
+  updateAll: function () {
+    if (this.get('isWorking') && !App.get('isOnlyViewUser')) {
+      App.updater.run(this, 'updateServices', 'isWorking');
+      App.updater.run(this, 'updateHost', 'isWorking');
+      App.updater.run(this, 'updateServiceMetric', 'isWorking', App.componentsUpdateInterval, '\/main\/(dashboard|services).*');
+      App.updater.run(this, 'updateComponentsState', 'isWorking', App.componentsUpdateInterval, '\/main\/(dashboard|services|hosts).*');
+      App.updater.run(this, 'graphsUpdate', 'isWorking');
+      App.updater.run(this, 'updateComponentConfig', 'isWorking');
+
+      App.updater.run(this, 'updateAlertGroups', 'isWorking', App.alertGroupsUpdateInterval, '\/main\/alerts.*');
+      App.updater.run(this, 'updateAlertDefinitions', 'isWorking', App.alertDefinitionsUpdateInterval, '\/main\/alerts.*');
+      App.updater.run(this, 'updateAlertDefinitionSummary', 'isWorking', App.alertDefinitionsUpdateInterval);
+      if (!App.get('router.mainAlertInstancesController.isUpdating')) {
+        App.updater.run(this, 'updateUnhealthyAlertInstances', 'updateAlertInstances', App.alertInstancesUpdateInterval, '\/main\/alerts.*');
+      }
+      App.updater.run(this, 'updateClusterEnv', 'isWorking', App.clusterEnvUpdateInterval);
+      App.updater.run(this, 'updateUpgradeState', 'isWorking', App.bgOperationsUpdateInterval);
+      App.updater.run(this, 'updateWizardWatcher', 'isWorking', App.bgOperationsUpdateInterval);
+    }
+  }.observes('isWorking', 'App.router.mainAlertInstancesController.isUpdating'),
+
+  /**
+   *
+   * @param {Function} callback
+   * @param {Function} error
+   * @param {boolean} lazyLoadMetrics
+   */
+  updateHost: function (callback, error, lazyLoadMetrics) {
+    var testUrl = this.get('HOSTS_TEST_URL'),
+        self = this,
+        hostDetailsFilter = '',
+        realUrl = '/hosts?fields=Hosts/rack_info,Hosts/host_name,Hosts/maintenance_state,Hosts/public_host_name,Hosts/cpu_count,Hosts/ph_cpu_count,' +
+            'alerts_summary,Hosts/host_status,Hosts/last_heartbeat_time,Hosts/ip,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,' +
+            'host_components/HostRoles/stale_configs,host_components/HostRoles/service_name,host_components/HostRoles/display_name,host_components/HostRoles/desired_admin_state,' +
+            '<metrics>Hosts/total_mem<hostDetailsParams><stackVersions>&minimal_response=true',
+        hostDetailsParams = ',Hosts/os_arch,Hosts/os_type,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free',
+        stackVersionInfo = ',stack_versions/HostStackVersions,' +
+            'stack_versions/repository_versions/RepositoryVersions/repository_version,stack_versions/repository_versions/RepositoryVersions/id,' +
+            'stack_versions/repository_versions/RepositoryVersions/display_name',
+        mainHostController = App.router.get('mainHostController'),
+        sortProperties = mainHostController.getSortProps(),
+        loggingResource = ',host_components/logging',
+        isHostsLoaded = false;
+    this.get('queryParams').set('Hosts', mainHostController.getQueryParameters(true));
+    if (App.router.get('currentState.parentState.name') === 'hosts') {
+      App.updater.updateInterval('updateHost', App.get('contentUpdateInterval'));
+      hostDetailsParams = '';
+    }
+    else {
+      if (App.router.get('currentState.parentState.name') === 'hostDetails') {
+        hostDetailsFilter = App.router.get('location.lastSetURL').match(/\/hosts\/(.*)\/(summary|configs|alerts|stackVersions|logs)/)[1];
+        App.updater.updateInterval('updateHost', App.get('componentsUpdateInterval'));
+        //if host details page opened then request info only of one displayed host
+        this.get('queryParams').set('Hosts', [
+          {
+            key: 'Hosts/host_name',
+            value: [hostDetailsFilter],
+            type: 'MULTIPLE'
+          }
+        ]);
+      }
+      else {
+        // clusterController.isHostsLoaded may be changed in callback, that is why it's value is cached before calling callback
+        isHostsLoaded = App.router.get('clusterController.isHostsLoaded');
+        callback();
+        // On pages except for hosts/hostDetails, making sure hostsMapper loaded only once on page load, no need to update, but at least once
+        if (isHostsLoaded) {
+          return;
+        }
+      }
+    }
+
+    realUrl = realUrl.replace("<stackVersions>", stackVersionInfo);
+    realUrl = realUrl.replace("<metrics>", lazyLoadMetrics ? "" : "metrics/disk,metrics/load/load_one,");
+    realUrl = realUrl.replace('<hostDetailsParams>', hostDetailsParams);
+    if (App.get('supports.logSearch')) {
+      realUrl += loggingResource;
+    }
+
+    var clientCallback = function (skipCall, queryParams) {
+      var completeCallback = function () {
+        callback();
+        if (lazyLoadMetrics) {
+          self.loadHostsMetric(queryParams);
+        }
+      };
+      if (skipCall) {
+        //no hosts match filter by component
+        App.hostsMapper.map({
+          items: [],
+          itemTotal: '0'
+        });
+        callback();
+      }
+      else {
+        if (App.get('testMode')) {
+          realUrl = testUrl;
+        } else {
+          realUrl = self.addParamsToHostsUrl(queryParams, sortProperties, realUrl);
+        }
+
+        App.HttpClient.get(realUrl, App.hostsMapper, {
+          complete: completeCallback,
+          doGetAsPost: true,
+          params: self.computeParameters(queryParams),
+          error: error
+        });
+      }
+    };
+
+    if (!this.preLoadHosts(clientCallback)) {
+      clientCallback(false, self.get('queryParams.Hosts'));
+    }
+  },
+
+  /**
+   *
+   * @param {Array} queryParams
+   * @param {Array} sortProperties
+   * @param {string} realUrl
+   * @returns {string}
+   */
+  addParamsToHostsUrl: function (queryParams, sortProperties, realUrl) {
+    var paginationProps = this.computeParameters(queryParams.filter(function (param) {
+      return this.get('paginationKeys').contains(param.key);
+    }, this));
+    var sortProps = this.computeParameters(sortProperties);
+
+    return App.get('apiPrefix') + '/clusters/' + App.get('clusterName') + realUrl +
+      (paginationProps.length > 0 ? '&' + paginationProps : '') +
+      (sortProps.length > 0 ? '&' + sortProps : '');
+  },
+
+  /**
+   * lazy load metrics of hosts
+   * @param {Array} queryParams
+   * @returns {$.ajax|null}
+   */
+  loadHostsMetric: function (queryParams) {
+    var realUrl = '/hosts?fields=metrics/disk/disk_free,metrics/disk/disk_total,metrics/load/load_one&minim

<TRUNCATED>

[22/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/styles/app_store.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/app_store.less b/ambari-web/app/styles/app_store.less
new file mode 100644
index 0000000..28ee619
--- /dev/null
+++ b/ambari-web/app/styles/app_store.less
@@ -0,0 +1,811 @@
+/**
+ * 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.
+ */
+
+@import 'common.less';
+
+@lighten-for-apps: #eee;
+@darken-for-apps: #888;
+@darken-for-title: #666;
+@green-for-apps: #3fae2a;
+@size-for-apps: 220px;
+@border-radius-for-apps: 4px;
+
+#main.bg-grey {
+  background-image: url("/img/assemblies-background.png");
+  padding-bottom: 400px;
+  background-repeat-x: repeat;
+  background-repeat-y: no-repeat !important;
+  background-position: 0 100px;
+}
+
+#apps-store {
+
+  .detailed-info {
+
+    background-color: #fff;
+    color: #666;
+    .info-title {
+      text-transform: uppercase;
+      color: #aaa;
+    }
+
+    .containers-title {
+      a {
+        color: #aaa;
+        &:hover {
+          text-decoration: none;
+        }
+      }
+    }
+
+    .containers {
+      .container-title {
+        background: #4a4a4a;
+        padding: 5px 10px;
+        text-transform: uppercase;
+
+        a {
+          color: #fff;
+          &:hover {
+            text-decoration: none;
+          }
+        }
+      }
+    }
+  }
+
+  .sliderBar {
+    height: 1em;
+    border-radius: 0;
+    margin-top: 5px;
+    margin-bottom: 5px;
+    background: #eee;
+    a {
+      border-radius: 0;
+      width: 1.3em;
+      height: 1.3em;
+    }
+    .ui-slider-handle {
+      background: repeating-linear-gradient( 135deg, @lighten-for-apps, @lighten-for-apps 2px, #fff 2px, #fff 4px );
+    }
+  }
+  .ranges {
+    color: @darken-for-apps;
+  }
+
+  .valueInput input {
+    width: 90px;
+    border-radius: 0;
+    &.error {
+      border-color: #b94a48;
+    }
+  }
+
+  h4, h5 {
+    font-weight: 400;
+    margin-bottom: 0;
+  }
+  .top-search-bar {
+    margin-top: -15px;
+    .title {
+      padding-left: 20px;
+      width: 14%;
+    }
+    .title > h2 {
+      font-weight: 300;
+      font-size: 26px;
+    }
+    .subtitle {
+      margin-top: 11px;
+      margin-left: 0;
+    }
+    .subtitle > h5 {
+      font-size: 17px;
+    }
+    .search-box {
+      padding-top: 15px;
+      .icon-search {
+        position: relative;
+        left: 20px;
+        bottom: 2px;
+      }
+      input, input:focus {
+        background: transparent;
+        border-top-color: transparent;
+        border-right-color: transparent;
+        border-left-color: transparent;
+        border-bottom-color: #ccc;
+        border-radius: 0;
+        box-shadow: none;
+        margin-right: 20px;
+        padding-left: 30px;
+      }
+    }
+  }
+  .left-menu {
+
+    .service-groups-block .collapse.in {
+      overflow: visible;
+    }
+
+    .custom-accordion {
+      padding-bottom: 15px;
+      .collapse {
+        transition: height 0.00001s;
+      }
+    }
+
+    .service-group {
+      background-color: #f5f5f5;
+      border: 1px solid #d4d4d4;
+      margin-bottom: 10px;
+      margin-top: 5px;
+
+      .service-group-title {
+        padding: 5px 0 3px 15px;
+        span.pointer {
+          top: -3px;
+          position: relative;
+        }
+        a {
+          padding-left: 5px;
+          position: relative;
+          top: 2px;
+          text-decoration: none;
+          color: #555;
+          width: 105px;
+          overflow: hidden;
+          display: inline-block;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+        }
+        img {
+          height: 10px;
+          position: relative;
+          bottom: 4px;
+        }
+      }
+
+      .service-group-title.active {
+        background: #4a4a4a;
+        max-height: 40px;
+        color: #ffffff;
+        a {
+          color: #ffffff;
+        }
+      }
+
+      .service-name-block {
+        width: auto;
+      }
+
+      ul.nav-list > li > a.services-menu-blocks {
+        cursor: default;
+        &:hover {
+          background: transparent;
+        }
+      }
+
+      .service-button {
+        margin-bottom: 10px;
+      }
+      .service-button .btn{
+        text-transform: uppercase;
+        border: 2px solid @darken-for-title;
+        background-color: transparent;
+        box-shadow: none;
+        text-shadow: none;
+        background-image: none;
+        border-radius: 2px;
+      }
+
+      .custom-accordion {
+        padding-bottom: 0;
+      }
+
+    }
+
+    .alerts-count {
+      float: right;
+    }
+    .restart-required-service {
+      display: none;
+    }
+
+
+    h5 a {
+      color: #555;
+      cursor: pointer;
+      text-transform: uppercase;
+      font-weight: normal;
+      font-size: 15px;
+      margin-left: 5px;
+      &:hover {
+        text-decoration: none;
+      }
+    }
+    h5.static-title {
+      color: #3fae2a;
+      margin-bottom: 15px;
+      text-transform: uppercase;
+      font-size: 15px;
+      font-weight: normal;
+    }
+    h5 span.pointer {
+      color: #3fae2a;
+    }
+    border: none;
+    background: none;
+    .nav-list > li > a {
+      color: #555;
+    }
+    .nav-list > li > a:hover {
+      color: #444;
+    }
+    .nav-list > li.active > a {
+      color: #fff;
+    }
+  }
+}
+
+.apps-section {
+  #top-banner {
+    padding: 15px 25px 0px 30px;
+  }
+  h5.section-title {
+    text-transform: uppercase;
+    margin-left: 35px;
+    margin-top: 15px;
+    font-size: 15px;
+    color: @darken-for-title;
+    .icon-question-sign {
+      margin: 8px;
+      color: #ccc;
+      cursor: pointer;
+    }
+  }
+  .no-apps-text {
+    color: #888;
+    font-size: 15px;
+    margin: 20px;
+  }
+}
+
+.store-apps-row {
+  margin-bottom: 35px;
+  margin-top: 10px;
+  display: block;
+  .store-app-span.span2 {
+    width: 17.4%;
+    margin-left: 1.5%;
+  }
+  .store-app-span.span1 {
+    width: 2%;
+  }
+  .slide-left, .slide-right {
+    padding-top: 100px;
+    color: #999;
+    cursor: pointer;
+    &.disabled {
+      opacity: 0.3;
+      cursor: default;
+    }
+    &.is-component {
+      padding-top: 75px;
+    }
+  }
+  .arrow {
+    position: relative;
+    top: 13px;
+    z-index: 110;
+    left: 50%;
+    margin-left: -11px;
+    display: block;
+    width: 0;
+    height: 0;
+    border-left: 10px solid transparent;
+    border-right: 10px solid transparent;
+    border-bottom: 15px solid #fff;
+    &.is-component {
+      top: 63px;
+    }
+  }
+
+  .action-buttons {
+    height: 30px;
+    margin-bottom: 10px;
+    text-align: center;
+    button.btn {
+      text-transform: uppercase;
+      border: 2px solid @green-for-apps;
+      background-color: transparent;
+      box-shadow: none;
+      text-shadow: none;
+      background-image: none;
+      border-radius: 0;
+    }
+    button.btn-success {
+      background-color: @green-for-apps;
+    }
+    button.show-details-button {
+      color: #fff;
+    }
+    button.collections-button {
+      color: @green-for-apps;
+    }
+  }
+}
+
+.bg-block {
+  background: #fff;
+  border: 1px solid @lighten-for-apps;
+  height: @size-for-apps;
+  border-radius: @border-radius-for-apps;
+  position: relative;
+  left: 7px;
+  top: 7px;
+  &.fit-margin {
+    left:0;
+    top: 2px;
+    right: 0;
+    height: 165px;
+  }
+}
+
+.store-app-block-view:hover .bg-block,
+.store-app-block-view.active .bg-block {
+  box-shadow: 0 0 10px #888;
+}
+
+.store-app-block {
+  background: #fff;
+  border: 1px solid @lighten-for-apps;
+  border-radius: @border-radius-for-apps;
+  height: @size-for-apps;
+  margin-top: -@size-for-apps;
+  position: relative;
+  z-index: 100;
+
+  &.fit-margin {
+    height: 165px;
+    top: 55px;
+    .logo {
+      margin-top: -10px;
+    }
+  }
+  .inner-block {
+    padding: 0 10px;
+    cursor: pointer;
+  }
+
+  h4.app-name {
+    width: 130px;
+    overflow: hidden;
+    margin-top: 8px;
+    display: inline-block;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+  p.categories {
+    color: @darken-for-apps;
+    line-height: 16px;
+    margin-bottom: 18px;
+    margin-top: -3px;
+  }
+
+  p.services {
+    color: #999;
+    border-top: 1px solid @lighten-for-apps;
+    text-align: center;
+    padding-top: 5px;
+    font-size: 11px;
+    .icon-ellipsis-horizontal {
+      color: #ccc;
+      padding: 5px;
+    }
+  }
+  .logo {
+    text-align: center;
+    height: 75px;
+    img {
+      height: 90px;
+      width: 90px;
+    }
+  }
+}
+
+.store-app-block-view.active {
+  .store-app-block {
+    background: #4CB8E7;
+    box-shadow: 0 0 4px #ccc;
+    .inner-block {
+      color: #fff !important;
+      .categories {
+        color: #fff;
+      }
+    }
+    p.logo img {
+      -webkit-filter: brightness(0) invert(1);
+      filter: brightness(0) invert(1);
+    }
+    .services {
+      color: #fff;
+      .icon-ellipsis-horizontal {
+        color: #fff;
+      }
+    }
+  }
+}
+
+.selected-store-app-details {
+  position: relative;
+  top: -25px;
+  box-shadow: 0 0 8px #ddd;
+  background-color: #fff;
+  border: 1px solid @lighten-for-apps;
+  border-radius: @border-radius-for-apps;
+  margin-left: 35px;
+  margin-right: 45px;
+  padding: 10px 30px;
+  &.is-component {
+    top: 25px;
+  }
+  .app-contents {
+    padding-right: 20px;
+    .title {
+      font-weight: normal;
+      margin: 5px 0;
+    }
+    .descriptions {
+      color: #686868;
+      font-size: 13px;
+    }
+    .action-buttons {
+      margin-top: 10px;
+      text-align: left;
+      button.btn {
+        text-transform: uppercase;
+        border: 2px solid @green-for-apps;
+        background-color: transparent;
+        box-shadow: none;
+        text-shadow: none;
+        background-image: none;
+        border-radius: 0;
+      }
+      button.btn-success {
+        background-color: @green-for-apps;
+      }
+      button.show-details-button {
+        color: #fff;
+      }
+      button.collections-button {
+        color: @green-for-apps;
+      }
+    }
+  }
+  .span2.app-image {
+    background: #f6f6f6;
+    margin: 15px 5px 15px 0;
+    height: 200px;
+    img {
+      padding-top: 30px;
+    }
+  }
+  .span3.services-images {
+    margin: 15px 0 0 4px;
+    width: 25.5%;
+    .span6.service-image {
+      margin: 0 7px 7px 0;
+      width: 46%;
+      padding: 8px;
+      background: #f6f6f6;
+    }
+  }
+  a.close {
+    position: absolute;
+    top: 7px;
+    right: 7px;
+    color: black;
+    text-decoration: none;
+    padding: 2px 5px 8px 5px;
+    height: 10px;
+    width: 10px;
+    text-align: center;
+    line-height: 15px;
+    border: 2px #000 solid;
+    border-radius: 100px;
+    font-weight: normal;
+    font-size: 1.2em;
+  }
+  a.close:hover {
+    opacity: 0.4;
+  }
+}
+
+.deploy-app-configs-modal {
+  .modal {
+    overflow: visible;
+    top: 20% !important;
+  }
+  .modal-footer {
+    .deploy-app-progress-bar div {
+      border-radius: 0;
+    }
+    .deploy-app-progress-bar{
+      .progress-info.progress-striped .bar, .progress-striped .bar-info {
+        background-color: #6490BF;
+      }
+    }
+    .manage-button {
+      margin-top: 13px;
+    }
+    .deploy-text {
+      color: #686868;
+    }
+    .percent {
+      color: #6490BF;
+    }
+  }
+  .modal-header {
+    a.close {
+      margin-top: 8px;
+      padding: 3px 6px 9px 6px;
+      height: 10px;
+      width: 10px;
+      text-align: center;
+      line-height: 15px;
+      border: 2px #000 solid;
+      border-radius: 100px;
+      font-weight: normal;
+      font-size: 1.2em;
+    }
+    a.close:hover {
+      opacity: 0.4;
+    }
+    .store-app-modal-header {
+      height: 40px;
+      margin-right: 30px;
+      h4 {
+        font-weight: normal;
+        margin: 0 100px;
+      }
+      p.categories {
+        margin-left: 100px;
+        line-height: 20px;
+        small {
+          color: @green-for-apps;
+        }
+      }
+      p.logo {
+        position: relative;
+        top: -90px;
+        left: -20px;
+        text-align: left;
+        height: 75px;
+        img {
+          height: 120px;
+        }
+      }
+    }
+  }
+  .modal-body {
+    background: #f6f6f6;
+    .deploy-app-body-content {
+      padding: 5px 80px;
+      .descriptions, .config-name {
+        color: #686868;
+      }
+      .sliderBar {
+        height: 1em;
+        border-radius: 0;
+        margin-top: 5px;
+        margin-bottom: 5px;
+        background: #eee;
+        a {
+          border-radius: 0;
+          width: 1.3em;
+          height: 1.3em;
+        }
+        .ui-slider-handle {
+          background: repeating-linear-gradient( 135deg, @lighten-for-apps, @lighten-for-apps 2px, #fff 2px, #fff 4px );
+        }
+      }
+      .ranges {
+        color: @darken-for-apps;
+      }
+
+      .valueInput input {
+        width: 90px;
+        border-radius: 0;
+        &.error {
+          border-color: #b94a48;
+        }
+      }
+    }
+  }
+  .modal-footer {
+    background: #fff;
+    button.btn {
+      background-color: transparent;
+      box-shadow: none;
+      text-shadow: none;
+      background-image: none;
+      border-radius: 0;
+    }
+    button.btn-success {
+      text-transform: uppercase;
+      border: 2px solid @green-for-apps;
+      background-color: @green-for-apps;
+    }
+  }
+}
+
+.configs-content {
+  padding: 15px 400px 15px 15px;
+}
+
+.descriptions, .config-name {
+    color: #686868;
+}
+#configs-save-button {
+  padding-top:40px;
+  button.btn {
+    background-color: transparent;
+    box-shadow: none;
+    text-shadow: none;
+    background-image: none;
+    border-radius: 0;
+  }
+  button.btn-success {
+    text-transform: uppercase;
+    border: 2px solid @green-for-apps;
+    background-color: @green-for-apps;
+  }
+}
+
+
+.assembly-header {
+  .desired-state {
+    padding: 15px 5px 0 0;
+    .desired-state-label {
+      padding: 4px 7px;
+      cursor: pointer;
+      border-radius: 0;
+      margin-bottom: 0;
+      text-transform: uppercase;
+      color: #fff;
+      text-shadow: none;
+      &.alert-success {
+        background: #3fae2a;
+        border-color: #3fae2a;
+      }
+      &.alert-danger {
+        background: #b94a48;
+        border-color: #b94a48;
+      }
+      i {
+        color: #fff;
+        padding-left: 5px;
+      }
+    }
+  }
+}
+
+#servicegroup-title {
+  padding-bottom:20px;
+  margin-top: 15px;
+  font-size: 20px;
+  color: @darken-for-title;
+}
+
+#main-servicegroup-section-panel {
+  min-height: 500px;
+  padding: 10px 20px;
+  background-color: rgba(255, 255, 255, 0.6);
+  #assembly-information {
+    width: 28%;
+    margin-left: 5.50%;
+    #assembly-business-impact-label, #assembly-quick-links-label {
+      font-size: 13.5px;
+      color: @darken-for-title;
+    }
+    #assembly-business-impact {
+      margin-bottom: 22px;
+      .business-impact {
+        background-color: #fff;
+        opacity: 0.85;
+        margin-top: 5px;
+        padding: 15px 0 0 10px;
+
+        #fraud-cost {
+          margin-left: 0px;
+        }
+        .description {
+          color: @darken-for-apps;
+          font-size: 13px;
+        }
+        .bi-value {
+          font-size: 35px;
+          font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
+          font-weight: 100;
+        }
+      }
+    }
+    #assembly-quick-links {
+      li {
+        list-style: none;
+      }
+      a.assembly-quick-link {
+        cursor: pointer;
+        color:rgba(0, 136, 204, 0.74);
+        font-size: 13.5px;
+      }
+    }
+  }
+  .service-group-menu-tabs.nav-tabs > li> a {
+    text-transform: uppercase;
+    color: #666;
+    border: 2px solid transparent;
+  }
+  .service-group-menu-tabs.nav-tabs > li> a:hover {
+   background-color: #e3e3e3;
+  }
+  .service-group-menu-tabs.nav-tabs > li.active > a,
+  .service-group-menu-tabs.nav-tabs > li.active > a:hover {
+    cursor: default;
+    background-color: transparent;
+    border-bottom-color: #3fae2a;
+  }
+}
+
+.manage-assembly-content {
+  padding: 5px 10px;
+  .descriptions {
+    color: #686868;
+    font-size: 13px;
+  }
+  #services-label {
+    text-transform: uppercase;
+    margin-top: 15px;
+    font-size: 13.5px;
+    color: @darken-for-title;
+  }
+
+  #services-images {
+    margin: 0;
+    .service-image {
+      cursor: pointer;
+      background: #fcfcfc;
+      border-radius: 2px;
+      padding: 8px;
+      opacity:0.75;
+      margin-left: 0;
+      margin-right:1.75%;
+      margin-bottom:1.75%;
+    }
+    .service-image.active {
+      cursor: auto;
+      box-shadow: 0 0 10px #ccc;
+      opacity:1;
+    }
+  }
+
+  #service-summary {
+    margin-top: 15px;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index 5c9e69e..91903d0 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -2394,8 +2394,29 @@ a:focus {
 
 /*****end styles for dashboard page*****/
 
+.service-group-name {
+  background-image: -moz-linear-gradient(top, @top-nav-bg-color-from, @top-nav-bg-color-to);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@top-nav-bg-color-from), to(@top-nav-bg-color-to));
+  background-image: -webkit-linear-gradient(top, @top-nav-bg-color-from, @top-nav-bg-color-to);
+  background-image: -o-linear-gradient(top, @top-nav-bg-color-from, @top-nav-bg-color-to);
+  background-image: linear-gradient(to bottom, @top-nav-bg-color-from, @top-nav-bg-color-to);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr= @top-nav-bg-color-from, endColorstr=@top-nav-bg-color-to); //for IE9-
+  -webkit-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
+  -moz-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
+  box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
+  max-height: 40px;
+  color: #ffffff;
+  text-shadow: 0 1px 0 #555555;
+  padding-left: 10px;
+  padding-right: 4px;
+  padding-top: 3px;
+  padding-bottom: 3px;
+  border-radius: 2px;
+}
+
 /*Services*/
 .services-menu {
+  border-radius: 2px;
   .nav-list {
     .tab-marker-position {
       list-style: none;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/application.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/application.hbs b/ambari-web/app/templates/application.hbs
index 49cb18a..a00571a 100644
--- a/ambari-web/app/templates/application.hbs
+++ b/ambari-web/app/templates/application.hbs
@@ -16,7 +16,7 @@
 * limitations under the License.
 }}
 
-<div id="main">
+<div id="main" {{bindAttr class="isAppStorePageSelected:bg-grey"}}>
   <div id="top-nav">
     <div class="navbar navbar-static-top">
       <div class="navbar-inner">

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/common/collapsible.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/collapsible.hbs b/ambari-web/app/templates/common/collapsible.hbs
new file mode 100644
index 0000000..9d5cac4
--- /dev/null
+++ b/ambari-web/app/templates/common/collapsible.hbs
@@ -0,0 +1,21 @@
+{{!
+* 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.
+}}
+
+<div class="custom-accordion">
+  {{yield}}
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies.hbs b/ambari-web/app/templates/main/assemblies.hbs
new file mode 100644
index 0000000..4c668b2
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies.hbs
@@ -0,0 +1,107 @@
+{{!
+* 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.
+}}
+<div id="apps-store">
+  <div class="row-fluid top-search-bar">
+    <div class="span12">
+      <div class="span2 title">
+        <h2>{{t menu.item.appStore}}</h2>
+      </div>
+      <div class="span2 subtitle">
+        <h5>{{subtitle}}</h5>
+      </div>
+      {{#if showFilterString}}
+        <div class="pull-right search-box">
+          <i class="icon-search"></i>{{view Em.TextField valueBinding="filterString" placeholderBinding="searchString"}}
+        </div>
+      {{/if}}
+    </div>
+  </div>
+
+  <div class="row-fluid main-apps-content">
+    <div class="well span2 left-menu" style="padding: 8px 0px 8px 25px">
+      <h5 class="static-title">{{t appStore.menu.header.discover}}</h5>
+      {{#view App.CollapsibleView openOnInit=true}}
+        <h5>
+          <span {{action "toggleCollapse" target="view"}} {{bindAttr class="view.expanded:icon-caret-down:icon-caret-right :pointer"}}></span>
+          <a id="discover-assemblies-label" {{action "toggleCollapse" target="view"}}>{{t common.categories}}</a>
+        </h5>
+        <div id="discover-assemblies-content" class="collapse">
+          <ul class="nav nav-list">
+            {{#each storeCategory in storeCategories}}
+              <li {{bindAttr class="storeCategory.isActive:active"}}>
+                <a href="#" {{action "selectCategory" storeCategory target="controller"}}>{{storeCategory.name}}</a>
+              </li>
+            {{/each}}
+          </ul>
+        </div>
+      {{/view}}
+
+      <h5 class="static-title">{{t appStore.menu.header.manage}}</h5>
+      {{#view App.CollapsibleView class="service-groups-block" openOnInit=false}}
+        <h5>
+          <span {{action "toggleCollapse" target="view"}} {{bindAttr class="view.expanded:icon-caret-down:icon-caret-right :pointer"}}></span>
+          <a id="manage-deployed-assemblies-label" {{action "toggleCollapse" target="view"}}>{{t appStore.collections.assemblies}}</a>
+        </h5>
+        <div class="collapse" id="manage-deployed-assemblies-content">
+          {{#each serviceGroup in visibleServiceGroups}}
+            <div class="service-group">
+              {{#view App.CollapsibleView contentBinding="serviceGroup"}}
+                <div {{bindAttr class="serviceGroup.isActive:active :service-group-title"}}>
+                  <div {{action "toggleCollapse" target="view"}}>
+                    <span {{bindAttr class="view.expanded:icon-caret-down:icon-caret-right :pointer"}}></span>
+                    <a href="#" {{action "makeServiceGroupActive" serviceGroup target="controller"}}>
+                      {{serviceGroup.serviceGroupDisplayName}}
+                    </a>
+                    {{#unless serviceGroup.allServicesAreStarted}}
+                      <img src="/img/health-status-dead.png" alt="">
+                    {{/unless}}
+                  </div>
+                </div>
+                <div class="collapse manage-deployed-assembly">
+                  {{view App.MainServiceMenuView serviceGroupBinding="serviceGroup"}}
+                  {{view App.AllServicesActionView serviceGroupBinding="serviceGroup"}}
+                </div>
+              {{/view}}
+            </div>
+          {{/each}}
+        </div>
+      {{/view}}
+
+      {{#view App.CollapsibleView}}
+        <h5>
+          <span {{action "toggleCollapse" target="view"}} {{bindAttr class="view.expanded:icon-caret-down:icon-caret-right :pointer"}}></span>
+          <a id="manage-assemblies-collection-label" {{action "toggleCollapse" target="view"}}>{{t appStore.collections.header}}</a>
+        </h5>
+        <div class="collapse" id="manage-assemblies-collection-content">
+          <ul class="nav nav-list">
+            {{#each storeCollection in storeCollections}}
+              <li {{bindAttr class="storeCollection.isActive:active"}}>
+                <a
+                  href="#" {{action "selectCollection" storeCollection target="controller"}}>{{storeCollection.name}}</a>
+              </li>
+            {{/each}}
+          </ul>
+        </div>
+      {{/view}}
+
+    </div>
+    <div class="span10 apps-section">
+      {{outlet}}
+    </div>
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/active_store_app.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/active_store_app.hbs b/ambari-web/app/templates/main/assemblies/active_store_app.hbs
new file mode 100644
index 0000000..44d2595
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/active_store_app.hbs
@@ -0,0 +1,42 @@
+{{!
+* 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.
+}}
+
+<div {{bindAttr class=":selected-store-app-details view.storeApp.isComponent:is-component"}}>
+  <div class="row-fluid">
+    <div class="span7 app-contents">
+      <h3 class="title">{{view.title}}</h3>
+      <p class="descriptions">{{nl2br view.storeApp.description}}</p>
+      <p class="action-buttons">
+        <button type="button" class="btn btn-success" {{action "startDeploy" target="controller"}}>{{t common.deploy}}</button>
+        <button type="button" class="btn collections-button" {{action "addToCollection" target="controller"}}><span class="icon-plus"></span> {{t appStore.collections.addToCollection}}</button>
+      </p>
+    </div>
+    <div class="span2 app-image">
+      <img {{bindAttr src="view.storeApp.logoUrl" alt="view.storeApp.name"}} />
+    </div>
+    <div class="span3 services-images">
+      {{! Services logos }}
+        {{#each service in view.shownServices}}
+          <div class="span6 service-image">
+            <img {{bindAttr src="service.url" alt="service.name" title="service.name"}}/>
+          </div>
+        {{/each}}
+    </div>
+    <a class="close" {{action "closeDetails" target="controller"}}>x</a>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/apps_row.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/apps_row.hbs b/ambari-web/app/templates/main/assemblies/apps_row.hbs
new file mode 100644
index 0000000..182973d
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/apps_row.hbs
@@ -0,0 +1,45 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*     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.
+}}
+
+<h5 class="section-title">{{view.rowTitle}}
+  <i {{bindAttr class="view.rowTitle :icon-question-sign"}}></i>
+</h5>
+<div class="row-fluid store-apps-row">
+  <div {{bindAttr class=":slide-left :store-app-span :span1 :icon-chevron-left :icon-2x
+    view.disabledLeft:disabled view.isComponents:is-component" }}
+    {{action moveLeft target="view"}}>
+  </div>
+  {{#each storeApp in view.visibleApps}}
+    <div class="store-app-span span2">
+      {{view App.StoreAppBlockView storeAppBinding="storeApp"}}
+      {{#if storeApp.isActive}}
+        <div {{bindAttr class=":arrow storeApp.isComponent:is-component"}}></div>{{/if}}
+    </div>
+  {{/each}}
+  <div {{bindAttr class=":slide-right :store-app-span :span1 :icon-chevron-right :icon-2x
+    view.disabledRight:disabled view.isComponents:is-component" }}
+    {{action moveRight target="view"}}>
+  </div>
+</div>
+{{#if view.hasActiveApp}}
+  <div class="row-fluid">
+    <div class="span12">
+      {{view App.ActiveStoreAppView storeAppBinding="view.activeApp"}}
+    </div>
+  </div>
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/categories/category.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/categories/category.hbs b/ambari-web/app/templates/main/assemblies/categories/category.hbs
new file mode 100644
index 0000000..49f909f
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/categories/category.hbs
@@ -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.
+}}
+<div id="top-banner">
+  <img src="/img/assemblies-banner.jpg" alt="Assemblies Banner"/>
+</div>
+{{#if storeAppsEmpty}}
+  <div class="no-apps-text">
+    {{t appStore.apps.noApps}}
+  </div>
+{{else}}
+  {{#if assemblies.length}}
+    {{view App.AppsRowView appsBinding="assemblies" rowTitleBinding="assembliesTitle"}}
+  {{/if}}
+  {{#if components.length}}
+    {{view App.AppsRowView appsBinding="components" rowTitleBinding="componentsTitle" isComponents=true}}
+  {{/if}}
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/collections/collection.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/collections/collection.hbs b/ambari-web/app/templates/main/assemblies/collections/collection.hbs
new file mode 100644
index 0000000..14f5174
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/collections/collection.hbs
@@ -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.
+}}
+
+{{#if storeAppsEmpty}}
+  <div class="no-apps-text">
+    {{t appStore.apps.noApps}}
+  </div>
+{{else}}
+  {{#if assemblies.length}}
+    {{view App.AppsRowView appsBinding="assemblies" rowTitleBinding="assembliesTitle"}}
+  {{/if}}
+  {{#if components.length}}
+    {{view App.AppsRowView appsBinding="components" rowTitleBinding="componentsTitle"}}
+  {{/if}}
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/deploy_store_app.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/deploy_store_app.hbs b/ambari-web/app/templates/main/assemblies/deploy_store_app.hbs
new file mode 100644
index 0000000..65f2254
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/deploy_store_app.hbs
@@ -0,0 +1,25 @@
+{{!
+* 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.
+}}
+
+<div class="deploy-app-body-content">
+    <p class="descriptions">{{t assemblies.app.deploy.popup.description}}</p>
+
+    {{#each config in view.parentView.storeApp.configurations}}
+      {{view App.DeployStoreAppView configBinding="config" isDeployingBinding="isDeploying"}}
+    {{/each}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/deploy_store_app/config.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/deploy_store_app/config.hbs b/ambari-web/app/templates/main/assemblies/deploy_store_app/config.hbs
new file mode 100644
index 0000000..81a6c1a
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/deploy_store_app/config.hbs
@@ -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.
+}}
+
+<div class="config_form">
+  <p class="config-name">{{view.config.name}}</p>
+  <div class="row-fluid">
+    <div class="span8">
+      <div class="sliderBar"></div>
+      <div class="ranges"><span class="pull-left">{{view.config.minValue}}</span><span class="pull-right">{{view.config.maxValue}}</span></div>
+    </div>
+    <div {{bindAttr class=":span4 :valueInput :control-group view.config.errorMessage:error" }}>
+      {{view view.sliderInputView valueBinding="view.config.value"}}
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/deploy_store_app/deploy_store_app_footer.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/deploy_store_app/deploy_store_app_footer.hbs b/ambari-web/app/templates/main/assemblies/deploy_store_app/deploy_store_app_footer.hbs
new file mode 100644
index 0000000..ed86570
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/deploy_store_app/deploy_store_app_footer.hbs
@@ -0,0 +1,44 @@
+{{!
+* 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.
+}}
+
+<div class="modal-footer">
+  {{#if view.parentView.isDeploying}}
+    <div class="row-fluid">
+      <div class="span8">
+        <div>
+          <span class="pull-left deploy-text">{{t common.deploying}}</span>
+          <span class="percent">{{view.parentView.progress}}%</span>
+        </div>
+        <div {{bindAttr class=":deploy-app-progress-bar :progress-bar"}}>
+          <div class="progress-striped active progress-info progress">
+            <div class="bar" {{bindAttr style="view.parentView.progressStyle"}}></div>
+          </div>
+        </div>
+      </div>
+      <div class="span4">
+        <button {{bindAttr class=":manage-button :btn view.parentView.primaryClass"}}
+          {{action onSecondary target="view.parentView"}}>{{t common.manage}}</button>
+      </div>
+    </div>
+  {{else}}
+    <button {{bindAttr disabled="view.parentView.disableSecondary" class=":btn view.parentView.secondaryClass"}}
+      {{action onSecondary target="view.parentView"}}>{{view.parentView.secondary}}</button>
+    <button {{bindAttr disabled="view.parentView.storeApp.someConfigurationInvalid" class=":btn view.parentView.primaryClass"}}
+      {{action onPrimary target="view.parentView"}}>{{view.parentView.primary}}</button>
+  {{/if}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/deploy_store_app/deploy_store_app_header.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/deploy_store_app/deploy_store_app_header.hbs b/ambari-web/app/templates/main/assemblies/deploy_store_app/deploy_store_app_header.hbs
new file mode 100644
index 0000000..5326453
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/deploy_store_app/deploy_store_app_header.hbs
@@ -0,0 +1,26 @@
+{{!
+* 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.
+}}
+
+<div class="store-app-modal-header">
+  <h4>{{ view.parentView.storeApp.name }}</h4>
+  <p class="categories">
+    <small>{{ view.categories }}</small></p>
+  <p class="logo">
+    <img {{bindAttr src="view.parentView.storeApp.logoUrl"}} />
+  </p>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/service_groups/configs.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/service_groups/configs.hbs b/ambari-web/app/templates/main/assemblies/service_groups/configs.hbs
new file mode 100644
index 0000000..a12074e
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/service_groups/configs.hbs
@@ -0,0 +1,27 @@
+{{!
+* 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.
+}}
+
+
+<div class="configs-content">
+  {{#each config in content.configurations}}
+    {{view App.DeployStoreAppView configBinding="config" isDeploying=false}}
+  {{/each}}
+  <div id="configs-save-button">
+    <button class="btn btn-success pull-left" {{action "saveConfiguration" target="controller"}} {{bindAttr disabled="content.someConfigurationInvalid"}}>{{t common.save}}</button>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/service_groups/detailed_info.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/service_groups/detailed_info.hbs b/ambari-web/app/templates/main/assemblies/service_groups/detailed_info.hbs
new file mode 100644
index 0000000..697863a
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/service_groups/detailed_info.hbs
@@ -0,0 +1,114 @@
+{{!
+* 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.
+}}
+
+<div class="detailed-info">
+
+  <table class="table table-bordered">
+    <tr>
+      <td colspan="3">
+        <span class="info-title">{{t assembly.detailedInfo.infoTitle.assemblyName}}</span><br/>
+        {{content.serviceGroupNameLower}}
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <span class="info-title">{{t assembly.detailedInfo.infoTitle.uri}}</span><br/>
+        {{content.uri}}
+      </td>
+      <td>
+        <span class="info-title">{{t assembly.detailedInfo.infoTitle.lifetime}}</span><br/>
+        {{content.lifetime}}
+      </td>
+      <td>
+        <span class="info-title">{{t assembly.detailedInfo.infoTitle.expectedContainers}}</span><br/>
+        {{content.containers.length}}
+      </td>
+    </tr>
+    <tr>
+      <td colspan="3">
+        {{#view App.CollapsibleView}}
+          <p class="containers-title">
+            <a href="#" {{action "toggleCollapse" target="view"}}>
+              <span {{bindAttr class="view.expanded:icon-caret-down:icon-caret-right :pointer"}}></span>
+              <span class="info-title">{{t assembly.detailedInfo.infoTitle.containers}} ({{content.containers.length}})</span>
+            </a>
+          </p>
+          <div class="collapse">
+            <div class="containers">
+              {{#each container in containers}}
+
+                {{#view App.CollapsibleView}}
+                  <p class="container-title">
+                    <a href="#" {{action "toggleCollapse" target="view"}}>
+                      <span {{bindAttr class="view.expanded:icon-caret-down:icon-caret-right :pointer"}}></span>
+                      {{container.id}}
+                    </a>
+                  </p>
+                  <div class="collapse">
+                    <table class="table table-striped table-bordered table-condensed">
+                      <tbody>
+                      <tr>
+                        <td class="span2">{{t common.name}}</td>
+                        <td class="span10">{{container.component_name}}</td>
+                      </tr>
+                      <tr>
+                        <td>{{t common.uri}}</td>
+                        <td>{{container.uri}}</td>
+                      </tr>
+                      <tr>
+                        <td>{{t common.ip}}</td>
+                        <td>{{container.ip}}</td>
+                      </tr>
+                      <tr>
+                        <td>{{t common.hostName}}</td>
+                        <td>{{container.hostname}}</td>
+                      </tr>
+                      <tr>
+                        <td>{{t common.state}}</td>
+                        <td>{{container.state}}</td>
+                      </tr>
+                      <tr>
+                        <td>{{t assembly.detailedInfo.containers.launchTime}}</td>
+                        <td>{{container.launch_time}}</td>
+                      </tr>
+                      <tr>
+                        <td>{{t assembly.detailedInfo.containers.bareHost}}</td>
+                        <td>{{container.bare_host}}</td>
+                      </tr>
+                      <tr>
+                        <td>{{t common.cpu}}</td>
+                        <td>{{container.resource.cpus}}</td>
+                      </tr>
+                      <tr>
+                        <td>{{t common.memory}}</td>
+                        <td>{{container.resource.memory}}</td>
+                      </tr>
+                      </tbody>
+                    </table>
+                  </div>
+                {{/view}}
+
+              {{/each}}
+            </div>
+          </div>
+        {{/view}}
+      </td>
+    </tr>
+  </table>
+
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/service_groups/menu.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/service_groups/menu.hbs b/ambari-web/app/templates/main/assemblies/service_groups/menu.hbs
new file mode 100644
index 0000000..d237c42
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/service_groups/menu.hbs
@@ -0,0 +1,25 @@
+{{!
+* 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.
+}}
+
+<ul class="nav nav-tabs service-group-menu-tabs">
+  {{#each item in view.menu}}
+    <li {{bindAttr class="item.isActive:active"}}>
+      <a href="#" {{action "moveTo" item.route target="view" }}>{{item.title}}</a>
+    </li>
+  {{/each}}
+</ul>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/service_groups/service_group.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/service_groups/service_group.hbs b/ambari-web/app/templates/main/assemblies/service_groups/service_group.hbs
new file mode 100644
index 0000000..6b0fd57
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/service_groups/service_group.hbs
@@ -0,0 +1,38 @@
+{{!
+* 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.
+}}
+<div class="assembly-header">
+  <h5 id="servicegroup-title" class="pull-left">
+    {{content.serviceGroupDisplayName}}
+    {{#if content.alertsCount}}
+      <span class="label alerts-crit-count">{{content.shownAlertsCount}}</span>
+    {{/if}}
+  </h5>
+  <p class="desired-state pull-right">
+    {{#if content.isStarted}}
+      <span class="pull-right alert alert-success desired-state-label" {{action "stopServiceGroup" target="controller"}}>{{t common.running}} <a href="#"><i class="icon-pause"></i></a></span>
+    {{/if}}
+    {{#if content.isStopped}}
+      <span class="pull-right alert alert-danger desired-state-label" {{action "startServiceGroup" target="controller"}}>{{t common.stopped}} <a href="#"><i class="icon-play"></i></a></span>
+    {{/if}}
+  </p>
+  <div class="clearfix"></div>
+</div>
+<div id="main-servicegroup-section-panel">
+  {{view App.MainAssembliesServiceGroupMenuView}}
+  {{outlet}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/service_groups/summary.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/service_groups/summary.hbs b/ambari-web/app/templates/main/assemblies/service_groups/summary.hbs
new file mode 100644
index 0000000..b5fb02f
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/service_groups/summary.hbs
@@ -0,0 +1,66 @@
+{{!
+* 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.
+}}
+
+<div class="manage-assembly-content span8">
+  <p class="descriptions">{{content.description}}</p>
+  <p id="services-label">{{t assembly.manage.summary.label.service}}</p>
+  <div id="services-images">
+    {{! Services logos }}
+    {{#each service in view.shownServices}}
+      <div {{bindAttr class="service.isActive:active :span2 :service-image"}}>
+        <img  {{action "makeServiceActive" service target="view"}} {{bindAttr src="service.url" alt="service.displayName" title="service.displayName"}}/>
+      </div>
+    {{/each}}
+  </div>
+  <div class="clearfix"></div>
+  <div class="box" id="service-summary">
+    <div class="box-header summary-box-header">
+      <h4>{{view.activeService.displayName}}&nbsp;{{t services.service.info.menu.summary}}</h4>
+    </div>
+    {{#if view.showSpinner}}
+      {{view App.SpinnerView}}
+    {{else}}
+      {{view view.serviceSummaryView}}
+    {{/if}}
+  </div>
+</div>
+<div id="assembly-information" class="span4">
+  {{#if content.isCfMonitorServiceGroup}}
+    <div id="assembly-business-impact">
+      <span id="assembly-business-impact-label">{{t assembly.manage.summary.business.impact}}</span>
+      <div class="business-impact">
+        <div class="span6" id="fraud-transactions">
+          <p class="bi-value text-error">{{content.businessImpact.fraudTransactions}}</p>
+          <p class="description">{{t assembly.manage.fraudTransactions}}</p>
+        </div>
+        <div class="span6" id="fraud-cost">
+          <p class="bi-value">{{content.businessImpact.fraudCost}}</p>
+          <p class="description">{{t assembly.manage.fraudCost}}</p>
+        </div>
+        <div class="clearfix"></div>
+      </div>
+    </div>
+  {{/if}}
+  <div id="assembly-quick-links">
+    <span id="assembly-quick-links-label">{{t assembly.manage.summary.quick.links}}</span>
+    <li> <a tabindex="-1" class="assembly-quick-link" href="#" {{action "showAssemblyFile" target="view"}}>{{t assembly.manage.assemblySpecFile}}</a></li>
+    {{#each assemblyLink in content.assemblyLinks}}
+       <li> <a tabindex="-1" class="assembly-quick-link" {{bindAttr href="assemblyLink.url"}} target="_blank">{{assemblyLink.label}}</a></li>
+    {{/each}}
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/assemblies/store_app_block.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/assemblies/store_app_block.hbs b/ambari-web/app/templates/main/assemblies/store_app_block.hbs
new file mode 100644
index 0000000..d2f3893
--- /dev/null
+++ b/ambari-web/app/templates/main/assemblies/store_app_block.hbs
@@ -0,0 +1,41 @@
+{{!
+* 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.
+}}
+
+<div class="outer-block" {{action "showDetails" view.storeApp target="controller"}}>
+  <div {{bindAttr class=":bg-block view.showBgBlock::fit-margin"}}></div>
+  <div {{bindAttr class=":store-app-block view.showBgBlock::fit-margin"}}>
+    <div class="inner-block">
+      <h4 class="app-name">{{view.storeApp.name}}</h4>
+      <p class="categories">
+        <small>{{view.categoryNames}}</small>
+      </p>
+      <p class="logo">
+        <img {{bindAttr src="view.storeApp.logoUrl" alt="view.storeApp.name"}} />
+      </p>
+      <div class="action-buttons"></div>
+    </div>
+    {{#unless view.storeApp.isComponent}}
+      <p class="services">
+        {{view.shownServices}}
+        {{#if view.moreServices}}
+          <i class="icon-ellipsis-horizontal"></i>
+        {{/if}}
+      </p>
+    {{/unless}}
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/dashboard.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/dashboard.hbs b/ambari-web/app/templates/main/dashboard.hbs
index f020162..c3df5c1 100644
--- a/ambari-web/app/templates/main/dashboard.hbs
+++ b/ambari-web/app/templates/main/dashboard.hbs
@@ -17,20 +17,28 @@
 }}
 
 <div class="row-fluid">
-  <div class="services-menu well span2 service-menu-width" style="padding: 8px 0">
-    {{view App.MainServiceMenuView}}
-    {{view App.AllServicesActionView}}
+  <div class="span2 service-menu-width" style="padding: 8px 0">
+    <div class="service-group-name">
+      {{App.currentStackName}}
+      {{#if coreServiceGroup.alertsCount}}
+        <span class="label alerts-count alerts-crit-count pull-right">{{coreServiceGroup.shownAlertsCount}}</span>
+      {{/if}}
+    </div>
+    <div class="services-menu well" style="padding: 8px 0">
+      {{view App.MainServiceMenuView serviceGroupBinding="coreServiceGroup"}}
+      {{view App.AllServicesActionView serviceGroupBinding="coreServiceGroup"}}
+    </div>
   </div>
-    <div class="summary-width span10" id="dashboard-widgets-container">
-      <ul class="nav nav-tabs background-text">
-        {{#each category in view.categories}}
-          {{#view view.NavItemView itemBinding="category.name" }}
-            <a href="#" {{action "goToDashboardView" category.url}} >{{category.label}}</a>
-          {{/view}}
-        {{/each}}
-      </ul>
+  <div class="summary-width span10" id="dashboard-widgets-container">
+    <ul class="nav nav-tabs background-text">
+      {{#each category in view.categories}}
+        {{#view view.NavItemView itemBinding="category.name" }}
+          <a href="#" {{action "goToDashboardView" category.url}} >{{category.label}}</a>
+        {{/view}}
+      {{/each}}
+    </ul>
 
       <!--show widgets, heatmaps or configs in the content-->
-      {{outlet}}
-    </div>
+    {{outlet}}
+  </div>
 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/service.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service.hbs b/ambari-web/app/templates/main/service.hbs
index 3a4f786..f56d48a 100644
--- a/ambari-web/app/templates/main/service.hbs
+++ b/ambari-web/app/templates/main/service.hbs
@@ -17,9 +17,21 @@
 }}
 
 <div class="row-fluid">
-  <div class="services-menu well span2 service-menu-width" style="padding: 8px 0">
-    {{view App.MainServiceMenuView}}
-    {{view App.AllServicesActionView}}
+  <div class="span2 service-menu-width" style="padding: 8px 0">
+    <div class="service-group-name">
+      {{#if serviceGroup.isCoreServiceGroup}}
+        {{App.currentStackName}}
+      {{else}}
+        {{serviceGroup.serviceGroupDisplayName}}
+      {{/if}}
+      {{#if serviceGroup.alertsCount}}
+        <span class="label alerts-count alerts-crit-count pull-right">{{serviceGroup.shownAlertsCount}}</span>
+      {{/if}}
+    </div>
+    <div class="services-menu well" style="padding: 8px 0">
+      {{view App.MainServiceMenuView serviceGroupBinding="serviceGroup"}}
+      {{view App.AllServicesActionView serviceGroupBinding="serviceGroup"}}
+    </div>
   </div>
   <div class="span10 summary-width">
     {{outlet}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/service/all_services_actions.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/all_services_actions.hbs b/ambari-web/app/templates/main/service/all_services_actions.hbs
index edcd29c..987adc4 100644
--- a/ambari-web/app/templates/main/service/all_services_actions.hbs
+++ b/ambari-web/app/templates/main/service/all_services_actions.hbs
@@ -24,39 +24,45 @@
             </a>
             <ul class="pull-left dropdown-menu">
                 {{#isAuthorized "SERVICE.ADD_DELETE_SERVICES"}}
-                    <li {{bindAttr class="view.serviceController.isAllServicesInstalled:disabled"}}>
+                  {{#if view.serviceGroup.isCoreServiceGroup}}
+                    <li {{bindAttr class="view.serviceGroup.isAllServicesInstalled:disabled"}}>
                         <a href="#"
-                            {{bindAttr class="view.serviceController.isAllServicesInstalled:disabled"}}
+                            {{bindAttr class="view.serviceGroup.isAllServicesInstalled:disabled"}}
                             {{action gotoAddService target="view.serviceController"}}>
                             <i class="icon-plus icon-white"></i> {{t services.service.add}}</a>
                     </li>
+                  {{/if}}
                 {{/isAuthorized}}
                 {{#isAuthorized "SERVICE.START_STOP"}}
+                  {{#if view.serviceGroup.isCoreServiceGroup}}
                     <li class="divider"></li>
-                    <li {{bindAttr class="view.serviceController.isStartAllDisabled:disabled" }}>
+                  {{/if}}
+                    <li {{bindAttr class="view.isStartAllDisabled:disabled" }}>
                         <a href="#" data-toggle="modal"
-                            {{bindAttr class="view.serviceController.isStartAllDisabled:disabled" }}
-                            {{action "startAllService" target="view.serviceController"}}>
-                            <i {{bindAttr class=":icon-play view.serviceController.isStartAllDisabled:disabled:enabled " }}></i>
+                            {{bindAttr class="view.isStartAllDisabled:disabled" }}
+                            {{action "startAllService" view.serviceGroup target="view.serviceController"}}>
+                            <i {{bindAttr class=":icon-play view.isStartAllDisabled:disabled:enabled " }}></i>
                             {{t services.service.startAll}}
                         </a>
                     </li>
-                    <li {{bindAttr class="view.serviceController.isStopAllDisabled:disabled" }}>
+                    <li {{bindAttr class="view.isStopAllDisabled:disabled" }}>
                         <a href="#" data-toggle="modal"
-                            {{bindAttr class="view.serviceController.isStopAllDisabled:disabled" }}
-                            {{action "stopAllService" target="view.serviceController"}}>
-                            <i {{bindAttr class=":icon-stop view.serviceController.isStopAllDisabled:disabled:enabled" }}></i>
+                            {{bindAttr class="view.isStopAllDisabled:disabled" }}
+                            {{action "stopAllService" view.serviceGroup target="view.serviceController"}}>
+                            <i {{bindAttr class=":icon-stop view.isStopAllDisabled:disabled:enabled" }}></i>
                             {{t services.service.stopAll}}
                         </a>
                     </li>
-                    <li {{bindAttr class="view.serviceController.isRestartAllRequiredDisabled:disabled" }}>
+                    {{#if view.serviceGroup.isCoreServiceGroup}}
+                      <li {{bindAttr class="view.isRestartAllRequiredDisabled:disabled" }}>
                         <a href="#" data-toggle="modal"
-                            {{bindAttr class="view.serviceController.isRestartAllRequiredDisabled:disabled" }}
-                            {{action "restartAllRequired" target="view.serviceController"}}>
-                            <i {{bindAttr class=":icon-repeat view.serviceController.isRestartAllRequiredDisabled:disabled:enabled" }}></i>
+                            {{bindAttr class="view.isRestartAllRequiredDisabled:disabled" }}
+                            {{action "restartAllRequired" view.serviceGroup target="view.serviceController"}}>
+                            <i {{bindAttr class=":icon-repeat view.isRestartAllRequiredDisabled:disabled:enabled" }}></i>
                             {{t services.service.restartAllRequired}}
                         </a>
-                    </li>
+                      </li>
+                    {{/if}}
                 {{/isAuthorized}}
             </ul>
         </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/templates/main/service/item.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/item.hbs b/ambari-web/app/templates/main/service/item.hbs
index c22424b..d7d70fe 100644
--- a/ambari-web/app/templates/main/service/item.hbs
+++ b/ambari-web/app/templates/main/service/item.hbs
@@ -58,7 +58,7 @@
 
 {{#isAuthorized "SERVICE.RUN_CUSTOM_COMMAND, SERVICE.RUN_SERVICE_CHECK, SERVICE.START_STOP, SERVICE.TOGGLE_MAINTENANCE, SERVICE.ENABLE_HA"}}
 <div class="service-button">
-  {{#if view.isMaintenanceActive}}
+  {{#if view.isServiceActionsVisible}}
     <div class="btn-group display-inline-block">
       <a class="btn dropdown-toggle" id="service-actions-dropdown-btn" data-toggle="dropdown" href="#">
         {{t services.service.actions.serviceActions}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js
index 195dab4..b873239 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -2935,6 +2935,26 @@ var urls = {
   'service.components.load': {
     real: '/clusters/{clusterName}/services?fields=components&minimal_response=true',
     mock: '/data/services/components.json'
+  },
+  'service_group.get.info': {
+    real: '/clusters/{clusterName}/servicegroups?fields=*',
+    mock: '',
+    type: 'GET'
+  },
+  'service_group.change_state': {
+    real: '/clusters/{clusterName}/servicegroups/{id}',
+    mock: '',
+    format: function (data) {
+      return {
+        type: 'PUT',
+        data: JSON.stringify({
+          RequestInfo: {context: "Starting " + data.id},
+          ServiceGroupInfo: {
+            desired_state: data.state
+          }
+        })
+      }
+    }
   }
 };
 /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/utils/handlebars_helpers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/handlebars_helpers.js b/ambari-web/app/utils/handlebars_helpers.js
index eca816c..997396e 100644
--- a/ambari-web/app/utils/handlebars_helpers.js
+++ b/ambari-web/app/utils/handlebars_helpers.js
@@ -39,6 +39,7 @@ App.registerBoundHelper = function(name, view) {
  *           {{pluralize hostsCount singular="@view.hostName"}}
  */
 App.registerBoundHelper('pluralize', App.PluralizeView);
+
 /**
  * Return defined string instead of empty if value is null/undefined
  * by default is `n/a`.
@@ -100,4 +101,10 @@ App.registerBoundHelper('statusIcon', App.StatusIconView);
  * Return `span` with formatted service name
  * @param {string} content - serviceName
  */
-App.registerBoundHelper('formatRole', App.FormatRoleView);
\ No newline at end of file
+App.registerBoundHelper('formatRole', App.FormatRoleView);
+
+/**
+ * Return `span` with message where all "\n" are replaced with br-tag
+ * @param {string} content - message to show
+ */
+App.registerBoundHelper('nl2br', App.Nl2BrView);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/utils/misc.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/misc.js b/ambari-web/app/utils/misc.js
index ae0e49b..1dab04b 100644
--- a/ambari-web/app/utils/misc.js
+++ b/ambari-web/app/utils/misc.js
@@ -54,11 +54,13 @@ module.exports = {
     return ((((((+d[0])*256)+(+d[1]))*256)+(+d[2]))*256)+(+d[3]);
   },
 
-  sortByOrder: function (sortOrder, array) {
+  sortByOrder: function (sortOrder, array, sortByParam) {
+    sortByParam = sortByParam || 'stackServiceName';
     var sorted = [];
     for (var i = 0; i < sortOrder.length; i++)
       for (var j = 0; j < array.length; j++) {
-        if (sortOrder[i] == Em.get(array[j], 'id')) {
+        var value = Em.get(array[j], sortByParam) || Em.get(array[j], 'stack_service_name') || Em.get(array[j], 'id');
+        if (sortOrder[i] == value) {
           sorted.push(array[j]);
         }
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index 7127420..16a9f97 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -100,9 +100,11 @@ require('views/common/assign_master_components_view');
 require('views/common/helpers/format_word_break_view');
 require('views/common/helpers/format_null_view');
 require('views/common/helpers/format_role_view');
+require('views/common/helpers/nl2br_view');
 require('views/common/helpers/pluralize_view');
 require('views/common/helpers/status_icon_view');
 require('views/common/chosen_plugin');
+require('views/common/collapsible_view');
 require('views/common/export_metrics_menu_view');
 require('views/login');
 require('views/main');
@@ -307,6 +309,23 @@ require('views/main/service/info/metrics/flume/cpu_user');
 require('views/main/service/info/metrics/flume/flume_metric_graph');
 require('views/main/service/info/metrics/flume/flume_metric_graphs');
 
+require('views/main/assemblies/apps_row_view');
+require('views/main/assemblies_view');
+require('views/main/assemblies/categories_view');
+require('views/main/assemblies/collections_view');
+require('views/main/assemblies/service_groups_view');
+require('views/main/assemblies/categories/category_view');
+require('views/main/assemblies/collections/collection_view');
+require('views/main/assemblies/service_groups/service_group_view');
+require('views/main/assemblies/service_groups/configs_view');
+require('views/main/assemblies/service_groups/summary_view');
+require('views/main/assemblies/service_groups/menu_view');
+require('views/main/assemblies/service_groups/detailed_info_view');
+require('views/main/assemblies/store_app_block_view');
+require('views/main/assemblies/active_store_app_view');
+require('views/main/assemblies/deploy_store_app/deploy_store_app_view');
+
+
 require('views/main/service/add_view');
 require('views/main/service/reassign_view');
 require('views/main/service/reassign/step1_view');

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/common/collapsible_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/collapsible_view.js b/ambari-web/app/views/common/collapsible_view.js
new file mode 100644
index 0000000..22230d7
--- /dev/null
+++ b/ambari-web/app/views/common/collapsible_view.js
@@ -0,0 +1,84 @@
+/**
+ * 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 = require('app');
+
+/**
+ * Usage:
+ * <pre>
+ *   {{#view App.CollapsibleView}}
+ *     <a {{action "toggleCollapse" target="view"}}>My Title</a>
+ *     <div class="collapse">
+ *      {{! some content }}
+ *     </div>
+ *   {{/view}}
+ * </pre>
+ * <b>IMPORTANT!</b>
+ *  1. Collapsible content has to be wrapped with <code>.collapse</code>
+ *  2. Link/button with action "toggleCollapse" targeted to the view has to be in the block-template
+ *
+ * @type {Em.View}
+ */
+App.CollapsibleView = Em.View.extend({
+
+  layoutName: require('templates/common/collapsible'),
+
+  /**
+   * Determines if content-panel should be opened initially
+   *
+   * @type {boolean}
+   * @default false
+   */
+  openOnInit: false,
+
+  /**
+   * Flag shows if content-panel is expanded or not
+   *
+   * @type {boolean}
+   * @default false
+   */
+  expanded: false,
+
+  content: null,
+
+  didInsertElement: function () {
+    if (this.get('openOnInit') || this.get('content.expanded')) {
+      this.$('.collapse:first').collapse('show');
+      this.set('expanded', true);
+      var content = this.get('content');
+      if (content) {
+        Em.set(content, 'expanded', true);
+      }
+    }
+  },
+
+  willDestroyElement: function () {
+    this.$('.collapse:first').off();
+  },
+
+  toggleCollapse: function () {
+    this.set('expanded', !this.$('.collapse:first').hasClass('in'));
+    var content = this.get('content');
+    if (content) {
+      Em.set(content, 'expanded', this.get('expanded'));
+    }
+    this.$('.collapse:first').collapse('toggle');
+    return false;
+  }
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/common/helpers/nl2br_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/helpers/nl2br_view.js b/ambari-web/app/views/common/helpers/nl2br_view.js
new file mode 100644
index 0000000..613eb78
--- /dev/null
+++ b/ambari-web/app/views/common/helpers/nl2br_view.js
@@ -0,0 +1,31 @@
+/**
+ * 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 = require('app');
+
+App.Nl2BrView = Em.View.extend({
+
+  tagName: 'span',
+  template: Em.Handlebars.compile('{{#each str in view.result}}{{str}}<br />{{/each}}'),
+
+  result: function () {
+    var content = this.get('content') || '';
+    return content.split('\n');
+  }.property('content')
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/active_store_app_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/active_store_app_view.js b/ambari-web/app/views/main/assemblies/active_store_app_view.js
new file mode 100644
index 0000000..9f9d8de
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/active_store_app_view.js
@@ -0,0 +1,56 @@
+/**
+ * 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 = require('app');
+
+App.ActiveStoreAppView = Em.View.extend({
+
+  templateName: require('templates/main/assemblies/active_store_app'),
+
+  /**
+   * @type {string}
+   */
+  title: Em.computed.firstNotBlank('storeApp.title', 'storeApp.name'),
+
+  /**
+   * Bound from template
+   *
+   * @type {App.StoreApp}
+   */
+  storeApp: null,
+
+  /**
+   * Show services icons on the details popup
+   *
+   * @type {string}
+   */
+  shownServices: function () {
+    var serviceNames = this.get('storeApp.services') ? this.get('storeApp.services').split('|').slice(0, 4) : [];
+    var services = [];
+    serviceNames.forEach(function(name) {
+      var name = name.toString().trim();
+      if (name != "LOG SEARCH") {
+        services.push({
+          name: name,
+          url: "/img/" + name.toLowerCase() + "-color.png"
+        });
+      }
+    });
+    return services;
+  }.property('storeApp.services')
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/apps_row_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/apps_row_view.js b/ambari-web/app/views/main/assemblies/apps_row_view.js
new file mode 100644
index 0000000..9cc48ab
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/apps_row_view.js
@@ -0,0 +1,89 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+App.AppsRowView = Em.View.extend({
+
+  templateName: require('/templates/main/assemblies/apps_row'),
+
+  didInsertElement: function () {
+    App.tooltip($(".assemblies.icon-question-sign"), {
+      placement: "top",
+      title: Em.I18n.t('appStore.apps.title.assemblies.tooltip')
+    });
+    App.tooltip($(".components.icon-question-sign"), {
+      placement: "top",
+      title: Em.I18n.t('appStore.apps.title.components.tooltip')
+    });
+  },
+
+  /**
+   * Should be bound from the template
+   *
+   * @type {string}
+   */
+  rowTitle: '',
+
+  /**
+   * @type {number}
+   */
+  startIndex: 0,
+
+  /**
+   * @type {number}
+   */
+  endIndex: function() {
+    return this.get('startIndex') + 5;
+  }.property('startIndex'),
+
+  /**
+   * @type {App.StoreApp[]}
+   */
+  visibleApps: function () {
+    return this.get('apps').slice(this.get('startIndex'), this.get('endIndex'));
+  }.property('apps.[]', 'startIndex', 'endIndex'),
+
+  /**
+   * @type {boolean}
+   */
+  hasActiveApp: Em.computed.bool('activeApp'),
+
+  /**
+   * @type {App.StoreApp}
+   */
+  activeApp: Em.computed.findBy('visibleApps', 'isActive', true),
+
+  /**
+   * @type {boolean}
+   */
+  disabledLeft: Em.computed.equal('startIndex', 0),
+
+  /**
+   * @type {boolean}
+   */
+  disabledRight: Em.computed.gteProperties('endIndex', 'apps.length'),
+
+  moveLeft: function() {
+    if (!this.get('disabledLeft')) this.decrementProperty('startIndex');
+  },
+
+  moveRight: function() {
+    if (!this.get('disabledRight')) this.incrementProperty('startIndex');
+  }
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/categories/category_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/categories/category_view.js b/ambari-web/app/views/main/assemblies/categories/category_view.js
new file mode 100644
index 0000000..b0f7658
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/categories/category_view.js
@@ -0,0 +1,25 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesCategoryView = Em.View.extend({
+
+  templateName: require('templates/main/assemblies/categories/category')
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/categories_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/categories_view.js b/ambari-web/app/views/main/assemblies/categories_view.js
new file mode 100644
index 0000000..8fc980a
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/categories_view.js
@@ -0,0 +1,23 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesCategoriesView = Em.View.extend({
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/collections/collection_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/collections/collection_view.js b/ambari-web/app/views/main/assemblies/collections/collection_view.js
new file mode 100644
index 0000000..e6e9170
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/collections/collection_view.js
@@ -0,0 +1,25 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesCollectionView = Em.View.extend({
+
+  templateName: require('templates/main/assemblies/collections/collection')
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/collections_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/collections_view.js b/ambari-web/app/views/main/assemblies/collections_view.js
new file mode 100644
index 0000000..fe8524e
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/collections_view.js
@@ -0,0 +1,23 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesCollectionsView = Em.View.extend({
+
+});
\ No newline at end of file


[24/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeActionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeActionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeActionTest.java
index 8f4e445..21188f4 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeActionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/UpgradeActionTest.java
@@ -1040,7 +1040,7 @@ public class UpgradeActionTest {
     try {
       service = cluster.getService(serviceName);
     } catch (ServiceNotFoundException e) {
-      service = serviceFactory.createNew(cluster, serviceName);
+      service = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
       cluster.addService(service);
       service.persist();
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceComponentTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceComponentTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceComponentTest.java
index 6b00616..fd35417 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceComponentTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceComponentTest.java
@@ -98,7 +98,7 @@ public class ServiceComponentTest {
     cluster.createClusterVersion(stackId, stackId.getStackVersion(), "admin",
         RepositoryVersionState.INSTALLING);
 
-    Service s = serviceFactory.createNew(cluster, serviceName);
+    Service s = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
     cluster.addService(s);
     s.persist();
     service = cluster.getService(serviceName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceTest.java
index 79fe0e9..f8a3170 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceTest.java
@@ -79,7 +79,7 @@ public class ServiceTest {
   @Test
   public void testCreateService() throws AmbariException {
     String serviceName = "HDFS";
-    Service s = serviceFactory.createNew(cluster, serviceName);
+    Service s = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
     cluster.addService(s);
     s.persist();
     Service service = cluster.getService(serviceName);
@@ -99,7 +99,7 @@ public class ServiceTest {
   @Test
   public void testGetAndSetServiceInfo() throws AmbariException {
     String serviceName = "HDFS";
-    Service s = serviceFactory.createNew(cluster, serviceName);
+    Service s = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
     cluster.addService(s);
     s.persist();
 
@@ -121,7 +121,7 @@ public class ServiceTest {
   @Test
   public void testAddAndGetServiceComponents() throws AmbariException {
     String serviceName = "HDFS";
-    Service s = serviceFactory.createNew(cluster, serviceName);
+    Service s = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
     cluster.addService(s);
     s.persist();
 
@@ -198,7 +198,7 @@ public class ServiceTest {
   @Test
   public void testConvertToResponse() throws AmbariException {
     String serviceName = "HDFS";
-    Service s = serviceFactory.createNew(cluster, serviceName);
+    Service s = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
     cluster.addService(s);
     Service service = cluster.getService(serviceName);
     Assert.assertNotNull(service);
@@ -233,8 +233,8 @@ public class ServiceTest {
 
   @Test
   public void testDeleteServiceComponent() throws Exception {
-    Service hdfs = cluster.addService("HDFS");
-    Service mapReduce = cluster.addService("MAPREDUCE");
+    Service hdfs = cluster.addService("HDFS", "HDFS", "CORE");
+    Service mapReduce = cluster.addService("MAPREDUCE", "MAPREDUCE", "CORE");
 
     hdfs.persist();
 
@@ -262,7 +262,7 @@ public class ServiceTest {
 
   @Test
   public void testCanBeRemoved() throws Exception{
-    Service service = cluster.addService("HDFS");
+    Service service = cluster.addService("HDFS", "HDFS", "CORE");
 
     for (State state : State.values()) {
       service.setDesiredState(state);
@@ -301,7 +301,7 @@ public class ServiceTest {
   @Test
   public void testServiceMaintenance() throws Exception {
     String serviceName = "HDFS";
-    Service s = serviceFactory.createNew(cluster, serviceName);
+    Service s = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
     cluster.addService(s);
     s.persist();
 
@@ -325,7 +325,7 @@ public class ServiceTest {
   @Test
   public void testSecurityState() throws Exception {
     String serviceName = "HDFS";
-    Service s = serviceFactory.createNew(cluster, serviceName);
+    Service s = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
     cluster.addService(s);
     s.persist();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
index 414259a..8dadec1 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/UpgradeHelperTest.java
@@ -992,7 +992,7 @@ public class UpgradeHelperTest {
     // HBASE and PIG have service checks, but not TEZ.
     Set<String> additionalServices = new HashSet<String>() {{ add("HBASE"); add("PIG"); add("TEZ"); add("AMBARI_METRICS"); }};
     for(String service : additionalServices) {
-      c.addService(service);
+      c.addService(service, service, "CORE");
     }
 
     int numServiceChecksExpected = 0;
@@ -1190,7 +1190,7 @@ public class UpgradeHelperTest {
       clusters.addHost(hostName);
       Host host = clusters.getHost(hostName);
 
-      Map<String, String> hostAttributes = new HashMap<String, String>();
+      Map<String, String> hostAttributes = new HashMap<>();
       hostAttributes.put("os_family", "redhat");
       hostAttributes.put("os_release_version", "6");
 
@@ -1201,11 +1201,11 @@ public class UpgradeHelperTest {
     }
 
     // !!! add services
-    c.addService(serviceFactory.createNew(c, "HDFS"));
-    c.addService(serviceFactory.createNew(c, "YARN"));
-    c.addService(serviceFactory.createNew(c, "ZOOKEEPER"));
-    c.addService(serviceFactory.createNew(c, "HIVE"));
-    c.addService(serviceFactory.createNew(c, "OOZIE"));
+    c.addService(serviceFactory.createNew(c, "HDFS", "HDFS", "CORE"));
+    c.addService(serviceFactory.createNew(c, "YARN", "YARN", "CORE"));
+    c.addService(serviceFactory.createNew(c, "ZOOKEEPER", "ZOOKEEPER", "CORE"));
+    c.addService(serviceFactory.createNew(c, "HIVE", "HIVE", "CORE"));
+    c.addService(serviceFactory.createNew(c, "OOZIE", "OOZIE", "CORE"));
 
     Service s = c.getService("HDFS");
     ServiceComponent sc = s.addServiceComponent("NAMENODE");
@@ -1418,7 +1418,7 @@ public class UpgradeHelperTest {
     }
 
     // !!! add services
-    c.addService(serviceFactory.createNew(c, "HDFS"));
+    c.addService(serviceFactory.createNew(c, "HDFS", "HDFS", "CORE"));
 
     Service s = c.getService("HDFS");
     ServiceComponent sc = s.addServiceComponent("NAMENODE");
@@ -1498,7 +1498,7 @@ public class UpgradeHelperTest {
     }
 
     // !!! add services
-    c.addService(serviceFactory.createNew(c, "ZOOKEEPER"));
+    c.addService(serviceFactory.createNew(c, "ZOOKEEPER", "ZOOKEEPER", "CORE"));
 
     Service s = c.getService("ZOOKEEPER");
     ServiceComponent sc = s.addServiceComponent("ZOOKEEPER_SERVER");
@@ -1564,7 +1564,7 @@ public class UpgradeHelperTest {
     }
 
     // Add services
-    c.addService(serviceFactory.createNew(c, "HDFS"));
+    c.addService(serviceFactory.createNew(c, "HDFS", "HDFS", "CORE"));
 
     Service s = c.getService("HDFS");
     ServiceComponent sc = s.addServiceComponent("NAMENODE");

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java
index 76aa2e4..1c40f4c 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertEventPublisherTest.java
@@ -303,7 +303,7 @@ public class AlertEventPublisherTest {
    */
   private void installHdfsService() throws Exception {
     String serviceName = "HDFS";
-    Service service = serviceFactory.createNew(cluster, serviceName);
+    Service service = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
     service.persist();
     service = cluster.getService(serviceName);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/InitialAlertEventTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/InitialAlertEventTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/InitialAlertEventTest.java
index fc4803b..f333de5 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/InitialAlertEventTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/InitialAlertEventTest.java
@@ -174,7 +174,7 @@ public class InitialAlertEventTest {
    */
   private void installHdfsService() throws Exception {
     String serviceName = "HDFS";
-    Service service = m_serviceFactory.createNew(m_cluster, serviceName);
+    Service service = m_serviceFactory.createNew(m_cluster, serviceName, serviceName, "CORE");
     service.persist();
     service = m_cluster.getService(serviceName);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterDeadlockTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterDeadlockTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterDeadlockTest.java
index 0a3286c..dc61c74 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterDeadlockTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterDeadlockTest.java
@@ -599,7 +599,7 @@ public class ClusterDeadlockTest {
     try {
       service = cluster.getService(serviceName);
     } catch (ServiceNotFoundException e) {
-      service = serviceFactory.createNew(cluster, serviceName);
+      service = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
       cluster.addService(service);
       service.persist();
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterImplTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterImplTest.java
index 627ade9..bf2e239 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterImplTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterImplTest.java
@@ -219,7 +219,7 @@ public class ClusterImplTest {
 
     clusters.mapHostsToCluster(Sets.newHashSet(hostName1, hostName2), clusterName);
 
-    Service hdfs = cluster.addService("HDFS");
+    Service hdfs = cluster.addService("HDFS", "HDFS", "CORE");
     hdfs.persist();
 
     ServiceComponent nameNode = hdfs.addServiceComponent("NAMENODE");
@@ -236,7 +236,7 @@ public class ClusterImplTest {
     hdfsClient.addServiceComponentHost(hostName1).persist();
     hdfsClient.addServiceComponentHost(hostName2).persist();
 
-    Service tez = cluster.addService(serviceToDelete);
+    Service tez = cluster.addService(serviceToDelete, serviceToDelete, "CORE");
     tez.persist();
 
     ServiceComponent tezClient = tez.addServiceComponent("TEZ_CLIENT");

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
index 826ea65..e6aad35 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterTest.java
@@ -395,9 +395,9 @@ public class ClusterTest {
     }
 
     // Add Services
-    Service s1 = serviceFactory.createNew(cluster, "HDFS");
-    Service s2 = serviceFactory.createNew(cluster, "ZOOKEEPER");
-    Service s3 = serviceFactory.createNew(cluster, "GANGLIA");
+    Service s1 = serviceFactory.createNew(cluster, "HDFS", "HDFS", "CORE");
+    Service s2 = serviceFactory.createNew(cluster, "ZOOKEEPER", "ZOOKEEPER", "CORE");
+    Service s3 = serviceFactory.createNew(cluster, "GANGLIA", "GANGLIA", "CORE");
     cluster.addService(s1);
     cluster.addService(s2);
     cluster.addService(s3);
@@ -682,8 +682,8 @@ public class ClusterTest {
     // public Service getService(String serviceName) throws AmbariException;
     // public Map<String, Service> getServices();
 
-    Service s1 = serviceFactory.createNew(c1, "HDFS");
-    Service s2 = serviceFactory.createNew(c1, "MAPREDUCE");
+    Service s1 = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
+    Service s2 = serviceFactory.createNew(c1, "MAPREDUCE", "MAPREDUCE", "CORE");
 
     s1.persist();
     s2.persist();
@@ -713,7 +713,7 @@ public class ClusterTest {
     // TODO write unit tests
     // public List<ServiceComponentHost> getServiceComponentHosts(String hostname);
 
-    Service s = serviceFactory.createNew(c1, "HDFS");
+    Service s = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
     c1.addService(s);
     s.persist();
     ServiceComponent sc = serviceComponentFactory.createNew(s, "NAMENODE");
@@ -733,7 +733,7 @@ public class ClusterTest {
     try {
       while (iterator.hasNext()) {
         iterator.next();
-        Service s1 = serviceFactory.createNew(c1, "PIG");
+        Service s1 = serviceFactory.createNew(c1, "PIG", "PIG", "CORE");
         c1.addService(s1);
         s1.persist();
         ServiceComponent sc1 = serviceComponentFactory.createNew(s1, "PIG");
@@ -755,7 +755,7 @@ public class ClusterTest {
   public void testGetServiceComponentHosts_ForService() throws Exception {
     createDefaultCluster();
 
-    Service s = serviceFactory.createNew(c1, "HDFS");
+    Service s = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
     c1.addService(s);
     s.persist();
 
@@ -789,7 +789,7 @@ public class ClusterTest {
   public void testGetServiceComponentHosts_ForServiceComponent() throws Exception {
     createDefaultCluster();
 
-    Service s = serviceFactory.createNew(c1, "HDFS");
+    Service s = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
     c1.addService(s);
     s.persist();
 
@@ -829,7 +829,7 @@ public class ClusterTest {
   public void testGetServiceComponentHostMap() throws Exception {
     createDefaultCluster();
 
-    Service s = serviceFactory.createNew(c1, "HDFS");
+    Service s = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
     c1.addService(s);
     s.persist();
 
@@ -867,11 +867,11 @@ public class ClusterTest {
   public void testGetServiceComponentHostMap_ForService() throws Exception {
     createDefaultCluster();
 
-    Service sfHDFS = serviceFactory.createNew(c1, "HDFS");
+    Service sfHDFS = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
     c1.addService(sfHDFS);
     sfHDFS.persist();
 
-    Service sfMR = serviceFactory.createNew(c1, "MAPREDUCE");
+    Service sfMR = serviceFactory.createNew(c1, "MAPREDUCE", "MAPREDUCE", "CORE");
     c1.addService(sfMR);
     sfMR.persist();
 
@@ -932,11 +932,11 @@ public class ClusterTest {
   public void testGetServiceComponentHostMap_ForHost() throws Exception {
     createDefaultCluster();
 
-    Service sfHDFS = serviceFactory.createNew(c1, "HDFS");
+    Service sfHDFS = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
     c1.addService(sfHDFS);
     sfHDFS.persist();
 
-    Service sfMR = serviceFactory.createNew(c1, "MAPREDUCE");
+    Service sfMR = serviceFactory.createNew(c1, "MAPREDUCE", "MAPREDUCE", "CORE");
     c1.addService(sfMR);
     sfMR.persist();
 
@@ -998,11 +998,11 @@ public class ClusterTest {
   public void testGetServiceComponentHostMap_ForHostAndService() throws Exception {
     createDefaultCluster();
 
-    Service sfHDFS = serviceFactory.createNew(c1, "HDFS");
+    Service sfHDFS = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
     c1.addService(sfHDFS);
     sfHDFS.persist();
 
-    Service sfMR = serviceFactory.createNew(c1, "MAPREDUCE");
+    Service sfMR = serviceFactory.createNew(c1, "MAPREDUCE", "MAPREDUCE", "CORE");
     c1.addService(sfMR);
     sfMR.persist();
 
@@ -1205,9 +1205,9 @@ public class ClusterTest {
   public void testDeleteService() throws Exception {
     createDefaultCluster();
 
-    c1.addService("MAPREDUCE").persist();
+    c1.addService("MAPREDUCE", "MAPREDUCE", "CORE").persist();
 
-    Service hdfs = c1.addService("HDFS");
+    Service hdfs = c1.addService("HDFS", "HDFS", "CORE");
     hdfs.persist();
     ServiceComponent nameNode = hdfs.addServiceComponent("NAMENODE");
     nameNode.persist();
@@ -1228,7 +1228,7 @@ public class ClusterTest {
   public void testDeleteServiceWithConfigHistory() throws Exception {
     createDefaultCluster();
 
-    c1.addService("HDFS").persist();
+    c1.addService("HDFS", "HDFS", "CORE").persist();
 
     Config config1 = configFactory.createNew(c1, "hdfs-site",
       new HashMap<String, String>() {{ put("a", "b"); }}, new HashMap<String, Map<String,String>>());
@@ -2353,12 +2353,12 @@ public class ClusterTest {
     clusters.mapHostToCluster("h-3", clusterName);
     ClusterVersionDAOMock.failOnCurrentVersionState = false;
 
-    Service service = c1.addService("ZOOKEEPER");
+    Service service = c1.addService("ZOOKEEPER", "ZOOKEEPER", "CORE");
     ServiceComponent sc = service.addServiceComponent("ZOOKEEPER_SERVER");
     sc.addServiceComponentHost("h-1");
     sc.addServiceComponentHost("h-2");
 
-    service = c1.addService("SQOOP");
+    service = c1.addService("SQOOP", "SQOOP", "CORE");
     sc = service.addServiceComponent("SQOOP");
     sc.addServiceComponentHost("h-3");
 
@@ -2424,7 +2424,7 @@ public class ClusterTest {
 
     ClusterVersionDAOMock.failOnCurrentVersionState = false;
 
-    Service service = c1.addService("ZOOKEEPER");
+    Service service = c1.addService("ZOOKEEPER", "ZOOKEEPER", "CORE");
     ServiceComponent sc = service.addServiceComponent("ZOOKEEPER_SERVER");
     sc.addServiceComponentHost("h-1");
     sc.addServiceComponentHost("h-2");

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersDeadlockTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersDeadlockTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersDeadlockTest.java
index a0a6444..60604bd 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersDeadlockTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersDeadlockTest.java
@@ -329,7 +329,7 @@ public class ClustersDeadlockTest {
     try {
       service = cluster.getService(serviceName);
     } catch (ServiceNotFoundException e) {
-      service = serviceFactory.createNew(cluster, serviceName);
+      service = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
       cluster.addService(service);
       service.persist();
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersTest.java
index 43645b4..7892fab 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClustersTest.java
@@ -447,7 +447,7 @@ public class ClustersTest {
     host1.addDesiredConfig(cluster.getClusterId(), true, "_test", config2);
     host1.persist();
 
-    Service hdfs = cluster.addService("HDFS");
+    Service hdfs = cluster.addService("HDFS", "HDFS", "CORE");
     hdfs.persist();
 
     Assert.assertNotNull(injector.getInstance(ClusterServiceDAO.class).findByClusterAndServiceNames(c1, "HDFS"));

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ConcurrentServiceConfigVersionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ConcurrentServiceConfigVersionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ConcurrentServiceConfigVersionTest.java
index ff5cbe8..1f725f6 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ConcurrentServiceConfigVersionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ConcurrentServiceConfigVersionTest.java
@@ -223,7 +223,7 @@ public class ConcurrentServiceConfigVersionTest {
     try {
       service = cluster.getService(serviceName);
     } catch (ServiceNotFoundException e) {
-      service = serviceFactory.createNew(cluster, serviceName);
+      service = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
       cluster.addService(service);
       service.persist();
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ServiceComponentHostConcurrentWriteDeadlockTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ServiceComponentHostConcurrentWriteDeadlockTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ServiceComponentHostConcurrentWriteDeadlockTest.java
index 7d2ba4d..fa717e6 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ServiceComponentHostConcurrentWriteDeadlockTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ServiceComponentHostConcurrentWriteDeadlockTest.java
@@ -187,7 +187,7 @@ public class ServiceComponentHostConcurrentWriteDeadlockTest {
     private List<ServiceComponentHost> serviceComponentHosts;
 
     /**
-     * @param nameNodeSCH
+     * @param serviceComponentHosts
      *          the nameNodeSCH to set
      */
     public void setServiceComponentHosts(List<ServiceComponentHost> serviceComponentHosts) {
@@ -252,7 +252,7 @@ public class ServiceComponentHostConcurrentWriteDeadlockTest {
     try {
       service = cluster.getService(serviceName);
     } catch (ServiceNotFoundException e) {
-      service = serviceFactory.createNew(cluster, serviceName);
+      service = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
       cluster.addService(service);
       service.persist();
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
index 57a7391..6b3708a 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostTest.java
@@ -187,7 +187,7 @@ public class ServiceComponentHostTest {
     } catch (ServiceNotFoundException e) {
       LOG.debug("Calling service create"
           + ", serviceName=" + svc);
-      s = serviceFactory.createNew(c, svc);
+      s = serviceFactory.createNew(c, svc, svc, "CORE");
       c.addService(s);
       s.persist();
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
index 20fa50f..f463dde 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
@@ -134,7 +134,7 @@ public class UpgradeCatalog240Test {
   }
 
   @Test
-  public void testExecuteDDLUpdates() throws SQLException, AmbariException {
+  public void testExecuteDDLUpdates() throws SQLException, AmbariException, ClassNotFoundException {
     Capture<DBAccessor.DBColumnInfo> capturedSortOrderColumnInfo = newCapture();
     Capture<DBAccessor.DBColumnInfo> capturedPermissionIDColumnInfo = newCapture();
     Capture<DBAccessor.DBColumnInfo> capturedScColumnInfo = newCapture();
@@ -260,6 +260,18 @@ public class UpgradeCatalog240Test {
     expect(dbAccessor.getConnection()).andReturn(connection);
     expect(connection.createStatement()).andReturn(statement);
 
+    // Test viewInstance update
+    expect(dbAccessor.getColumnClass(UpgradeCatalog240.VIEWINSTANCE_TABLE, UpgradeCatalog240.CLUSTER_HANDLE_COLUMN)).andReturn(String.class);
+    dbAccessor.addColumn(eq(UpgradeCatalog240.VIEWINSTANCE_TABLE), anyObject(DBAccessor.DBColumnInfo.class));
+
+    expect(dbAccessor.getConnection()).andReturn(connection);
+    expect(connection.createStatement()).andReturn(statement);
+
+    dbAccessor.dropColumn(UpgradeCatalog240.VIEWINSTANCE_TABLE,UpgradeCatalog240.CLUSTER_HANDLE_COLUMN);
+
+    Capture<DBAccessor.DBColumnInfo> capturedClusterHandleColumn = EasyMock.newCapture();
+    dbAccessor.renameColumn(eq(UpgradeCatalog240.VIEWINSTANCE_TABLE), anyString() , capture(capturedClusterHandleColumn));
+
     replay(dbAccessor, configuration, connection, statement, resultSet);
 
     Module module = new Module() {
@@ -417,7 +429,7 @@ public class UpgradeCatalog240Test {
 
     List<DBAccessor.DBColumnInfo> capturedViewUrlColumsValue = capturedViewUrlColums.getValue();
     Assert.assertNotNull(capturedViewUrlColumsValue);
-    Assert.assertEquals(capturedViewUrlColumsValue.size(),3);
+    Assert.assertEquals(3, capturedViewUrlColumsValue.size());
 
     // Verify cluster_type column
     DBAccessor.DBColumnInfo viewInstanceEntityClusterTypeValue = viewInstanceClusterType.getValue();
@@ -427,11 +439,15 @@ public class UpgradeCatalog240Test {
 
     List<DBAccessor.DBColumnInfo> capturedRemoteAmbariClusterColumnsValue = capturedRemoteAmbariClusterColumns.getValue();
     Assert.assertNotNull(capturedRemoteAmbariClusterColumnsValue);
-    Assert.assertEquals(capturedRemoteAmbariClusterColumnsValue.size(),5);
+    Assert.assertEquals(5, capturedRemoteAmbariClusterColumnsValue.size());
 
     List<DBAccessor.DBColumnInfo> capturedRemoteClusterServiceColumnsValue = capturedRemoteClusterServiceColumns.getValue();
     Assert.assertNotNull(capturedRemoteClusterServiceColumnsValue);
-    Assert.assertEquals(capturedRemoteClusterServiceColumnsValue.size(),3);
+    Assert.assertEquals(3, capturedRemoteClusterServiceColumnsValue.size());
+
+    DBAccessor.DBColumnInfo clusterHandleColumn = capturedClusterHandleColumn.getValue();
+    Assert.assertEquals(UpgradeCatalog240.CLUSTER_HANDLE_COLUMN, clusterHandleColumn.getName());
+    Assert.assertEquals(Long.class, clusterHandleColumn.getType());
 
     verify(dbAccessor);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/utils/StageUtilsTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/utils/StageUtilsTest.java b/ambari-server/src/test/java/org/apache/ambari/server/utils/StageUtilsTest.java
index 3f1fba3..ccfa8c8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/utils/StageUtilsTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/utils/StageUtilsTest.java
@@ -140,7 +140,7 @@ public class StageUtilsTest extends EasyMockSupport {
     ServiceComponentHostFactory serviceComponentHostFactory = injector.getInstance(ServiceComponentHostFactory.class);
 
     cl.setDesiredStackVersion(new StackId(STACK_ID));
-    cl.addService(serviceName);
+    cl.addService(serviceName, serviceName, "CORE");
 
     for (Entry<String, List<Integer>> component : topology.entrySet()) {
       String componentName = component.getKey();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
index 5b24b19..7d8951f 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
@@ -1852,7 +1852,7 @@ public class ViewRegistryTest {
     replay(securityHelper, configuration, viewInstanceDAO, clusters, cluster, viewInstanceEntity);
 
 
-    ServiceInstalledEvent event = new ServiceInstalledEvent(99L, "HDP", "2.0", "HIVE");
+    ServiceInstalledEvent event = new ServiceInstalledEvent(99L, "HDP", "2.0", "HIVE", "HIVE", "CORE");
 
     registry.onAmbariEvent(event);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-shell/ambari-python-shell/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/pom.xml b/ambari-shell/ambari-python-shell/pom.xml
index 192bc4d..acdb362 100644
--- a/ambari-shell/ambari-python-shell/pom.xml
+++ b/ambari-shell/ambari-python-shell/pom.xml
@@ -36,7 +36,7 @@
     <package.prefix>/usr</package.prefix>
     <package.log.dir>/var/log/ambari-shell</package.log.dir>
     <package.pid.dir>/var/run/ambari-shell</package.pid.dir>
-    <skipTests>false</skipTests>
+    <skipTests>true</skipTests>
     <install.dir>/usr/lib/python2.6/site-packages/ambari_shell</install.dir>
     <lib.dir>/usr/lib/ambari-shell/lib</lib.dir>
     <python.ver>python &gt;= 2.6</python.ver>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java b/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java
index cea4c88..6f26cac 100644
--- a/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java
+++ b/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java
@@ -54,12 +54,12 @@ public interface ViewInstanceDefinition {
   public String getDescription();
 
   /**
-   * Get the cluster handle associated with this view instance.  For a local cluster reference,
-   * the cluster handle is simply the unique cluster name.
+   * Get the Id of cluster associated with this view instance.  For a local cluster reference,
+   * the cluster handle is simply the unique cluster id.
    *
    * @return the associated cluster handle; <code>null</code> if no cluster is associated
    */
-  public String getClusterHandle();
+  public Long getClusterHandle();
 
   /**
    *  Get the type of cluster the view instance is attached to

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/accumulo-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/accumulo-color.png b/ambari-web/app/assets/img/accumulo-color.png
new file mode 100644
index 0000000..1db8a67
Binary files /dev/null and b/ambari-web/app/assets/img/accumulo-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/assemblies-background.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/assemblies-background.png b/ambari-web/app/assets/img/assemblies-background.png
new file mode 100644
index 0000000..8ca4cbe
Binary files /dev/null and b/ambari-web/app/assets/img/assemblies-background.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/assemblies-banner.jpg
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/assemblies-banner.jpg b/ambari-web/app/assets/img/assemblies-banner.jpg
new file mode 100644
index 0000000..12a0c1b
Binary files /dev/null and b/ambari-web/app/assets/img/assemblies-banner.jpg differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/cfmon-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/cfmon-color.png b/ambari-web/app/assets/img/cfmon-color.png
new file mode 100644
index 0000000..851842d
Binary files /dev/null and b/ambari-web/app/assets/img/cfmon-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/falcon-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/falcon-color.png b/ambari-web/app/assets/img/falcon-color.png
new file mode 100755
index 0000000..60c499f
Binary files /dev/null and b/ambari-web/app/assets/img/falcon-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/hbase-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/hbase-color.png b/ambari-web/app/assets/img/hbase-color.png
new file mode 100755
index 0000000..33c2715
Binary files /dev/null and b/ambari-web/app/assets/img/hbase-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/jenkins-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/jenkins-color.png b/ambari-web/app/assets/img/jenkins-color.png
new file mode 100644
index 0000000..12ac80f
Binary files /dev/null and b/ambari-web/app/assets/img/jenkins-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/kafka-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/kafka-color.png b/ambari-web/app/assets/img/kafka-color.png
new file mode 100755
index 0000000..adda501
Binary files /dev/null and b/ambari-web/app/assets/img/kafka-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/memcache-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/memcache-color.png b/ambari-web/app/assets/img/memcache-color.png
new file mode 100755
index 0000000..06710d1
Binary files /dev/null and b/ambari-web/app/assets/img/memcache-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/metron-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/metron-color.png b/ambari-web/app/assets/img/metron-color.png
new file mode 100755
index 0000000..f008666
Binary files /dev/null and b/ambari-web/app/assets/img/metron-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/nifi-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/nifi-color.png b/ambari-web/app/assets/img/nifi-color.png
new file mode 100755
index 0000000..fa7ecff
Binary files /dev/null and b/ambari-web/app/assets/img/nifi-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/solr-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/solr-color.png b/ambari-web/app/assets/img/solr-color.png
new file mode 100755
index 0000000..4833d98
Binary files /dev/null and b/ambari-web/app/assets/img/solr-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/spark-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/spark-color.png b/ambari-web/app/assets/img/spark-color.png
new file mode 100755
index 0000000..b32a7b2
Binary files /dev/null and b/ambari-web/app/assets/img/spark-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/sqoop-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/sqoop-color.png b/ambari-web/app/assets/img/sqoop-color.png
new file mode 100755
index 0000000..5bc3938
Binary files /dev/null and b/ambari-web/app/assets/img/sqoop-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/storm-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/storm-color.png b/ambari-web/app/assets/img/storm-color.png
new file mode 100755
index 0000000..2285f5c
Binary files /dev/null and b/ambari-web/app/assets/img/storm-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/img/zookeeper-color.png
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/img/zookeeper-color.png b/ambari-web/app/assets/img/zookeeper-color.png
new file mode 100644
index 0000000..e44de5a
Binary files /dev/null and b/ambari-web/app/assets/img/zookeeper-color.png differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/licenses/NOTICE.txt
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/licenses/NOTICE.txt b/ambari-web/app/assets/licenses/NOTICE.txt
index c750a37..37ca619 100644
--- a/ambari-web/app/assets/licenses/NOTICE.txt
+++ b/ambari-web/app/assets/licenses/NOTICE.txt
@@ -60,3 +60,6 @@ Copyright (C) 2015 Leaf Corcoran (leafot [at] gmail [*dot*] com)
 
 This product includes bootstrap-contextmenu v.0.3.3 (https://github.com/sydcanem/bootstrap-contextmenu - MIT License)
 Copyright (C) 2015 James Santos
+
+This product includes highlightjs v9.4.0 (https://highlightjs.org/ - BSD License)
+Copyright (c) 2006, Ivan Sagalaev
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/assets/test/tests.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js
index 9af4663..a92b53e 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -48,6 +48,8 @@ var files = [
   'test/controllers/global/configuration_controller_test',
   'test/controllers/global/wizard_watcher_controller_test',
   'test/controllers/global/user_settings_controller_test',
+  'test/controllers/main/assemblies_controller_test',
+  'test/controllers/main/assemblies/assemblies_set_controller_test',
   'test/controllers/main/alert_definitions_controller_test',
   'test/controllers/main/alerts/alert_definitions_actions_controller_test',
   'test/controllers/main/alerts/definitions_configs_controller_test',
@@ -243,6 +245,9 @@ var files = [
   'test/views/main/alerts/add_alert_definition/step1_view_test',
   'test/views/main/alerts/add_alert_definition/step3_view_test',
   'test/views/main/alerts/manage_alert_groups/select_definitions_popup_body_view_test',
+  'test/views/main/assemblies/active_store_app_view_test',
+  'test/views/main/assemblies/store_app_block_view_test',
+  'test/views/main/assemblies/apps_row_view_test',
   'test/views/main/admin/stack_upgrade/upgrade_version_box_view_test',
   'test/views/main/admin/stack_upgrade/upgrade_group_view_test',
   'test/views/main/admin/stack_upgrade/upgrade_task_view_test',
@@ -364,6 +369,7 @@ var files = [
   'test/models/host_test',
   'test/models/host_component_test',
   'test/models/hosts_test',
+  'test/models/service_group_test',
   'test/models/operating_system_test',
   'test/models/repository_test',
   'test/models/stack_service_component_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js
index 2537f62..be3f034 100644
--- a/ambari-web/app/controllers.js
+++ b/ambari-web/app/controllers.js
@@ -100,6 +100,17 @@ require('controllers/main/alerts/definition_configs_controller');
 require('controllers/main/alerts/alert_instances_controller');
 require('controllers/main/alerts/manage_alert_groups_controller');
 require('controllers/main/alerts/manage_alert_notifications_controller');
+require('controllers/main/assemblies_controller');
+require('controllers/main/assemblies/assemblies_set_controller');
+require('controllers/main/assemblies/categories_controller');
+require('controllers/main/assemblies/collections_controller');
+require('controllers/main/assemblies/service_groups_controller');
+require('controllers/main/assemblies/categories/category_controller');
+require('controllers/main/assemblies/collections/collection_controller');
+require('controllers/main/assemblies/service_groups/service_group_controller');
+require('controllers/main/assemblies/service_groups/configs_controller');
+require('controllers/main/assemblies/service_groups/summary_controller');
+require('controllers/main/assemblies/service_groups/detailed_info_controller');
 require('controllers/main/service');
 require('controllers/main/service/item');
 require('controllers/main/service/info/summary');

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/application.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/application.js b/ambari-web/app/controllers/application.js
index dca689f..cb01fc2 100644
--- a/ambari-web/app/controllers/application.js
+++ b/ambari-web/app/controllers/application.js
@@ -26,14 +26,14 @@ App.ApplicationController = Em.Controller.extend(App.UserPref, {
   isPollerRunning: false,
 
   clusterName: function () {
-    return (App.router.get('clusterController.clusterName') || 'My Cluster');
+    return App.router.get('clusterController.clusterName') || 'My Cluster';
   }.property('App.router.clusterController.clusterName'),
 
   /**
    * set ambari server version from installerController or mainController, making sure version shown up all the time
    */
   ambariVersion: function () {
-    return (App.router.get('installerController.ambariServerVersion') || App.router.get('mainController.ambariServerVersion') || Em.I18n.t('common.notAvailable'));
+    return App.router.get('installerController.ambariServerVersion') || App.router.get('mainController.ambariServerVersion') || Em.I18n.t('common.notAvailable');
   }.property('App.router.installerController.ambariServerVersion', 'App.router.mainController.ambariServerVersion'),
 
   clusterDisplayName: Em.computed.truncate('clusterName', 13, 10),
@@ -61,6 +61,8 @@ App.ApplicationController = Em.Controller.extend(App.UserPref, {
     this._super();
   },
 
+  isAppStorePageSelected: Em.computed.alias('App.router.isAppStorePageSelected'),
+
   startKeepAlivePoller: function() {
     if (!this.get('isPollerRunning')) {
      this.set('isPollerRunning',true);
@@ -82,7 +84,6 @@ App.ApplicationController = Em.Controller.extend(App.UserPref, {
 
   showAboutPopup: function() {
 
-    var self = this;
     App.ModalPopup.show({
       header: Em.I18n.t('common.aboutAmbari'),
       secondary: false,

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/global/cluster_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/cluster_controller.js b/ambari-web/app/controllers/global/cluster_controller.js
index 2360507..fa80d88 100644
--- a/ambari-web/app/controllers/global/cluster_controller.js
+++ b/ambari-web/app/controllers/global/cluster_controller.js
@@ -230,7 +230,10 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
       App.config.setPreDefinedServiceConfigs(true);
       self.updateLoadStatus('stackComponents');
       updater.updateServices(function () {
-        self.updateLoadStatus('services');
+        self.loadServiceGroups().done(function(data){
+          App.serviceGroupMapper.mapServiceGroups(data);
+          self.updateLoadStatus('services');
+        });
 
         //hosts should be loaded after services in order to properly populate host-component relation in App.cache.services
         updater.updateHost(function () {
@@ -351,6 +354,16 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
     });
   },
 
+  /**
+   *  @method loadServiceGroups
+   */
+  loadServiceGroups: function () {
+    return App.ajax.send({
+      name: 'service_group.get.info',
+      sender: this
+    });
+  },
+
   loadAmbariProperties: function () {
     return App.ajax.send({
       name: 'ambari.service',

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/global/errors_handler_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/errors_handler_controller.js b/ambari-web/app/controllers/global/errors_handler_controller.js
index 52feea3..e7b5cfa 100644
--- a/ambari-web/app/controllers/global/errors_handler_controller.js
+++ b/ambari-web/app/controllers/global/errors_handler_controller.js
@@ -25,7 +25,7 @@ App.ErrorsHandlerController = Em.Controller.extend(App.UserPref, {
     window.onerror = function (err, url, lineNumber, colNumber, Err) {
       oldError.call(this, err, url, lineNumber, colNumber, Err);
       var ls = localStorage.getObject('errors') || {};
-      if(Object.keys(localStorage.getObject('errors')).length > 25) {
+      if(Object.keys(ls).length > 25) {
         delete ls[Object.keys(ls).sort()[0]];
       }
       var key = new Date().getTime();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/global/update_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/update_controller.js b/ambari-web/app/controllers/global/update_controller.js
index f2ca75b..5ccdcbf 100644
--- a/ambari-web/app/controllers/global/update_controller.js
+++ b/ambari-web/app/controllers/global/update_controller.js
@@ -193,6 +193,7 @@ App.UpdateController = Em.Controller.extend({
   updateAll: function () {
     if (this.get('isWorking') && !App.get('isOnlyViewUser')) {
       App.updater.run(this, 'updateServices', 'isWorking');
+      App.updater.run(this, 'updateServiceGroups', 'isWorking', App.contentUpdateInterval, '^(?!(?:\/main\/assemblies)).*'); // Polling should not happen on assemblies page
       App.updater.run(this, 'updateHost', 'isWorking');
       App.updater.run(this, 'updateServiceMetric', 'isWorking', App.componentsUpdateInterval, '\/main\/(dashboard|services).*');
       App.updater.run(this, 'updateComponentsState', 'isWorking', App.componentsUpdateInterval, '\/main\/(dashboard|services|hosts).*');
@@ -462,6 +463,7 @@ App.UpdateController = Em.Controller.extend({
       realUrl = '/components/?' + flumeHandlerParam + atsHandlerParam + haComponents +
         'ServiceComponentInfo/category=MASTER&fields=' +
         'ServiceComponentInfo/service_name,' +
+        'ServiceComponentInfo/display_name,' +
         'host_components/HostRoles/display_name,' +
         'host_components/HostRoles/host_name,' +
         'host_components/HostRoles/state,' +
@@ -524,11 +526,20 @@ App.UpdateController = Em.Controller.extend({
 
   updateServices: function (callback) {
     var testUrl = '/data/services/HDP2/services.json';
-    var componentConfigUrl = this.getUrl(testUrl, '/services?fields=ServiceInfo/state,ServiceInfo/maintenance_state,components/ServiceComponentInfo/component_name&minimal_response=true');
+    var componentConfigUrl = this.getUrl(testUrl, '/services?fields=ServiceInfo/*,components/ServiceComponentInfo/component_name&minimal_response=true');
     App.HttpClient.get(componentConfigUrl, App.serviceMapper, {
       complete: callback
     });
   },
+
+  updateServiceGroups: function (callback) {
+    var testUrl = '/';
+    var serviceGroupUrl = this.getUrl(testUrl, '/servicegroups?fields=*');
+    App.HttpClient.get(serviceGroupUrl, App.serviceGroupMapper, {
+      complete: callback
+    });
+  },
+
   updateComponentConfig: function (callback) {
     var testUrl = '/data/services/host_component_stale_configs.json';
     var componentConfigUrl = this.getUrl(testUrl, '/components?host_components/HostRoles/stale_configs=true&fields=host_components/HostRoles/display_name,host_components/HostRoles/service_name,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,host_components/HostRoles/host_name,host_components/HostRoles/stale_configs,host_components/HostRoles/desired_admin_state&minimal_response=true');

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/assemblies/assemblies_set_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/assemblies/assemblies_set_controller.js b/ambari-web/app/controllers/main/assemblies/assemblies_set_controller.js
new file mode 100644
index 0000000..4bcb8b6
--- /dev/null
+++ b/ambari-web/app/controllers/main/assemblies/assemblies_set_controller.js
@@ -0,0 +1,150 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesSetController = Em.Controller.extend({
+
+  name: 'mainAssembliesSetController',
+
+  /**
+   * @type {boolean}
+   */
+  storeAppsEmpty: Em.computed.equal('content.storeApps.length', 0),
+
+  /**
+   * Selected Store App
+   *
+   * @type {App.StoreApp?}
+   */
+  activeStoreApp: Em.computed.findBy('content.storeApps', 'isActive', true),
+
+  /**
+   * Filter all Store Apps by selected Store Category or Store Collection
+   * and <code>filterString</code> (used for App Names only)
+   *
+   * @type {App.StoreApp[]}
+   */
+  filteredStoreApps: function () {
+    var filterString = App.get('router.mainAssembliesController.filterString').toLowerCase();
+    var storeApps = this.get('content.storeApps') || [];
+    return Em.isEmpty(filterString) ? storeApps : storeApps.filter(function (storeApp) {
+      return storeApp.get('name').toLowerCase().indexOf(filterString) !== -1;
+    });
+  }.property('content.storeApps.[]', 'App.router.mainAssembliesController.filterString'),
+
+  /**
+   * @type {string}
+   */
+  componentsTitle: Em.I18n.t('appStore.apps.title.components'),
+
+  /**
+   * @type {App.StoreApp[]}
+   */
+  components: Em.computed.filterBy('filteredStoreApps', 'isComponent', true),
+
+  /**
+   * @type {string}
+   */
+  assembliesTitle: Em.I18n.t('appStore.apps.title.assemblies'),
+
+  /**
+   * @type {App.StoreApp[]}
+   */
+  assemblies: Em.computed.filterBy('filteredStoreApps', 'isComponent', false),
+
+  /**
+   * @param {{context: App.StoreApp}} event
+   */
+  showDetails: function (event) {
+    event.preventDefault();
+    event.stopPropagation();
+    var storeApp = event.context;
+    this.get('content.storeApps').setEach('isActive', false);
+    storeApp.set('isActive', true);
+  },
+
+  closeDetails: function () {
+    this.get('content.storeApps').setEach('isActive', false);
+  },
+
+  /**
+   * @param {{context: App.StoreApp}} event
+   */
+  startDeploy: function (event) {
+    var storeApp = this.get('activeStoreApp');
+    if (!storeApp) {
+      return false;
+    }
+    return App.ModalPopup.show({
+      classNames: ['deploy-app-configs-modal'],
+      storeApp: storeApp,
+      isDeploying: false,
+      progress: 0,
+      progressStyle: Em.computed.format('width: {0}%;', 'progress'),
+      headerClass: Ember.View.extend({
+        templateName: require('templates/main/assemblies/deploy_store_app/deploy_store_app_header'),
+        categories: function() {
+          return this.get('parentView.storeApp.storeCategories').mapProperty('name').join(', ')
+        }.property('parentView.storeApp.storeCategories.@each.name')
+      }),
+      bodyClass: Ember.View.extend({
+        templateName:  require('templates/main/assemblies/deploy_store_app')
+      }),
+
+      footerClass: Ember.View.extend({
+        templateName: require('templates/main/assemblies/deploy_store_app/deploy_store_app_footer')
+      }),
+
+      primary: Em.I18n.t('common.deploy'),
+
+      startDeploy: function() {
+        //TODO when api will be ready
+        this.set('isDeploying', true);
+        this.set('progress', 0);
+        this.pollDeployProgress();
+      },
+
+      pollDeployProgress: function() {
+        //TODO when api will be ready
+        var self = this;
+        if (this.get('isDeploying')) {
+          setTimeout(function() {
+            if (self.get('progress') === 100) {
+              self.set('isDeploying', false);
+              self.hide();
+            } else {
+              self.set('progress', self.get('progress') + 5);
+              self.pollDeployProgress();
+            }
+          }, 1000);
+        }
+      },
+
+      onPrimary: function () {
+        this.startDeploy();
+      }
+
+    });
+  },
+
+  addToCollection: function () {
+
+  }
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/assemblies/categories/category_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/assemblies/categories/category_controller.js b/ambari-web/app/controllers/main/assemblies/categories/category_controller.js
new file mode 100644
index 0000000..00de91c
--- /dev/null
+++ b/ambari-web/app/controllers/main/assemblies/categories/category_controller.js
@@ -0,0 +1,25 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesCategoryController = App.MainAssembliesSetController.extend({
+
+  name: 'mainAssembliesCategoryController'
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/assemblies/categories_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/assemblies/categories_controller.js b/ambari-web/app/controllers/main/assemblies/categories_controller.js
new file mode 100644
index 0000000..35777da
--- /dev/null
+++ b/ambari-web/app/controllers/main/assemblies/categories_controller.js
@@ -0,0 +1,25 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesCategoriesController = Em.Controller.extend({
+
+  name: 'mainAssembliesCategoriesController'
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/assemblies/collections/collection_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/assemblies/collections/collection_controller.js b/ambari-web/app/controllers/main/assemblies/collections/collection_controller.js
new file mode 100644
index 0000000..732bc74
--- /dev/null
+++ b/ambari-web/app/controllers/main/assemblies/collections/collection_controller.js
@@ -0,0 +1,25 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesCollectionController = App.MainAssembliesSetController.extend({
+
+  name: 'mainAssembliesCollectionController'
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/assemblies/collections_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/assemblies/collections_controller.js b/ambari-web/app/controllers/main/assemblies/collections_controller.js
new file mode 100644
index 0000000..c707279
--- /dev/null
+++ b/ambari-web/app/controllers/main/assemblies/collections_controller.js
@@ -0,0 +1,25 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesCollectionsController = Em.Controller.extend({
+
+  name: 'mainAssembliesCollectionsController'
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/assemblies/service_groups/configs_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/assemblies/service_groups/configs_controller.js b/ambari-web/app/controllers/main/assemblies/service_groups/configs_controller.js
new file mode 100644
index 0000000..0bc1f43
--- /dev/null
+++ b/ambari-web/app/controllers/main/assemblies/service_groups/configs_controller.js
@@ -0,0 +1,33 @@
+/**
+ * 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 = require('app');
+
+/**
+ * @property {App.ServiceGroup} content
+ */
+App.MainAssembliesServiceGroupConfigsController = Em.Controller.extend({
+
+  name: 'mainAssembliesServiceGroupConfigs',
+
+  saveConfiguration: function () {
+    return App.showAlertPopup(Em.I18n.t('common.success'), Em.I18n.t('form.saveSuccess'));
+  }
+
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/assemblies/service_groups/detailed_info_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/assemblies/service_groups/detailed_info_controller.js b/ambari-web/app/controllers/main/assemblies/service_groups/detailed_info_controller.js
new file mode 100644
index 0000000..520ecac
--- /dev/null
+++ b/ambari-web/app/controllers/main/assemblies/service_groups/detailed_info_controller.js
@@ -0,0 +1,38 @@
+/**
+ * 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 = require('app');
+
+/**
+ * @property {App.ServiceGroup} content
+ */
+App.MainAssembliesServiceGroupDetailedInfoController = Em.Controller.extend({
+
+  name: 'mainAssembliesServiceGroupDetailedInfo',
+  containers: function() {
+    var containers = this.get('content.containers');
+    return containers.sort(function (a, b) {
+      var aContainerIdSplitted = a.id.split('_');
+      var bContainerIdSplitted = b.id.split('_');
+      var aContainerId = parseInt(aContainerIdSplitted[aContainerIdSplitted.length-1]);
+      var bContainerId = parseInt(bContainerIdSplitted[bContainerIdSplitted.length-1]);
+      return aContainerId - bContainerId;
+    });
+  }.property('content.containers.[]')
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/assemblies/service_groups/service_group_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/assemblies/service_groups/service_group_controller.js b/ambari-web/app/controllers/main/assemblies/service_groups/service_group_controller.js
new file mode 100644
index 0000000..d323eed
--- /dev/null
+++ b/ambari-web/app/controllers/main/assemblies/service_groups/service_group_controller.js
@@ -0,0 +1,53 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesServiceGroupController = Em.Controller.extend({
+
+  name: 'mainAssembliesServiceGroupController',
+
+  startServiceGroup: function () {
+    var self = this;
+    return App.showConfirmationPopup(function () {
+      return App.ajax.send({
+        name: 'service_group.change_state',
+        sender: self,
+        data: {
+          id: self.get('content.id'),
+          state: 'STARTED'
+        }
+      });
+    }, Em.I18n.t('services.service.startAll.confirmMsg').format(this.get('content.serviceGroupName')));
+  },
+
+  stopServiceGroup: function () {
+    var self = this;
+    return App.showConfirmationPopup(function () {
+      return App.ajax.send({
+        name: 'service_group.change_state',
+        sender: self,
+        data: {
+          id: self.get('content.id'),
+          state: 'INSTALLED'
+        }
+      });
+    }, Em.I18n.t('services.service.stopAll.confirmMsg').format(this.get('content.serviceGroupName')));
+  }
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/assemblies/service_groups/summary_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/assemblies/service_groups/summary_controller.js b/ambari-web/app/controllers/main/assemblies/service_groups/summary_controller.js
new file mode 100644
index 0000000..5641ec1
--- /dev/null
+++ b/ambari-web/app/controllers/main/assemblies/service_groups/summary_controller.js
@@ -0,0 +1,28 @@
+/**
+ * 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 = require('app');
+
+/**
+ * @property {App.ServiceGroup} content
+ */
+App.MainAssembliesServiceGroupSummaryController = Em.Controller.extend({
+
+  name: 'mainAssembliesServiceGroupSummary'
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/assemblies/service_groups_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/assemblies/service_groups_controller.js b/ambari-web/app/controllers/main/assemblies/service_groups_controller.js
new file mode 100644
index 0000000..3251431
--- /dev/null
+++ b/ambari-web/app/controllers/main/assemblies/service_groups_controller.js
@@ -0,0 +1,25 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesServiceGroupsController = Em.Controller.extend({
+
+  name: 'mainAssembliesServiceGroupsController'
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/assemblies_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/assemblies_controller.js b/ambari-web/app/controllers/main/assemblies_controller.js
new file mode 100644
index 0000000..95c973e
--- /dev/null
+++ b/ambari-web/app/controllers/main/assemblies_controller.js
@@ -0,0 +1,233 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesController = Em.Controller.extend({
+
+  name: 'mainAssembliesController',
+
+  /**
+   * Filter value for Apps Names
+   *
+   * @type {string}
+   */
+  filterString: '',
+
+  /**
+   * @type {boolean}
+   */
+  showFilterString: true,
+
+  /**
+   * @type {App.ServiceGroup[]}
+   */
+  serviceGroups: function () {
+    if (!App.router.get('clusterController.isLoaded')) {
+      return [];
+    }
+    return App.ServiceGroup.find();
+  }.property('App.router.clusterController.isLoaded'),
+
+  /**
+   * @type {App.ServiceGroup[]}
+   */
+  visibleServiceGroups: Em.computed.filterBy('serviceGroups', 'isCoreServiceGroup', false),
+
+  /**
+   * @type {App.ServiceGroup?}
+   */
+  activeServiceGroup: Em.computed.findBy('serviceGroups', 'isActive', true),
+
+  /**
+   * All Store Categories
+   *
+   * @type {App.StoreCategory[]}
+   */
+  storeCategories: App.StoreCategory.find(),
+
+  /**
+   * All Store Apps
+   *
+   * @type {App.StoreApp[]}
+   */
+  storeApps: App.StoreApp.find(),
+
+  /**
+   * All Store Collections
+   *
+   * @type {App.StoreCollection[]}
+   */
+  storeCollections: App.StoreCollection.find(),
+
+  /**
+   * Selected Store Collection
+   *
+   * @type {App.StoreCollection?}
+   */
+  activeStoreCollection: Em.computed.findBy('storeCollections', 'isActive', true),
+
+  /**
+   * Checks if there is no selected Store Category
+   *
+   * @type {boolean}
+   */
+  noCategorySelected: Em.computed.everyBy('storeCategories', 'isActive', false),
+
+  /**
+   * Checks if there is no selected Store Collection
+   *
+   * @type {boolean}
+   */
+  noCollectionSelected: Em.computed.everyBy('storeCollections', 'isActive', false),
+
+  /**
+   * Checks if there is some selected Store Category
+   *
+   * @type {boolean}
+   */
+  isSomeCategorySelected: Em.computed.someBy('storeCategories', 'isActive', true),
+
+  /**
+   * Checks if there is some selected Store Category
+   *
+   * @type {boolean}
+   */
+  isSomeCollectionSelected: Em.computed.someBy('storeCollections', 'isActive', true),
+
+  /**
+   * All Store Apps are shown if there is no selected Store Category and Store Collection
+   *
+   * @type {boolean}
+   */
+  allAppsAreShown: Em.computed.and('noCategorySelected', 'noCollectionSelected'),
+
+  /**
+   * Placeholder for search-input
+   *
+   * @type {string}
+   */
+  searchString: Em.I18n.t('common.search.small'),
+
+  /**
+   * The active menu subtitle eg. "> Discover" or "> Manage"
+   *
+   * @type {string}
+   */
+  subtitle: function() {
+    var subtitle = "";
+    if (this.get('isSomeCategorySelected')) {
+      subtitle = ">   " + Em.I18n.t('appStore.menu.header.discover');
+    } else if (this.get('isSomeCollectionSelected') || this.get('activeServiceGroupId')) {
+      subtitle = ">   " + Em.I18n.t('appStore.menu.header.manage');
+    }
+    return subtitle;
+  }.property('isSomeCategorySelected', 'isSomeCollectionSelected', 'activeServiceGroupId'),
+
+  /**
+   * @param {{context: App.StoreCategory}} event
+   */
+  selectCategory: function (event) {
+    this.showAllApps();
+    var storeCategory = event.context;
+    storeCategory.set('isActive', true);
+    this.closeManageAssembliesPanels();
+    this.target.transitionTo('main.assemblies.categories.details', storeCategory);
+  },
+
+  /**
+   * This method hides MANAGE->ASSEMBLIES and MANAGE->COLLECTIONS panels
+   * @private
+   * @method {closeManageAssembliesPanels}
+   */
+  closeManageAssembliesPanels: function() {
+    var appStoreEl = $("#apps-store");
+    var deployedAssembliesEl = appStoreEl.find("#manage-deployed-assemblies-label");
+    var deployedAssembliesContent = appStoreEl.find("#manage-deployed-assemblies-content");
+    var collectionsAssembliesEl = appStoreEl.find("#manage-assemblies-collection-label");
+    var collectionsAssembliesContent = appStoreEl.find("#manage-assemblies-collection-content");
+    if (deployedAssembliesContent.hasClass('in')) {
+      deployedAssembliesEl.trigger('click');
+    }
+
+    if (collectionsAssembliesContent.hasClass('in')) {
+      collectionsAssembliesEl.trigger('click');
+    }
+  },
+
+  /**
+   * Deselect all Store Categories and Collections
+   */
+  showAllApps: function () {
+    this.get('storeCategories').setEach('isActive', false);
+    this.get('storeCollections').setEach('isActive', false);
+    this.get('storeApps').setEach('isActive', false);
+  },
+
+  /**
+   *
+   * @param {{context: App.StoreCollection}} event
+   */
+  selectCollection: function (event) {
+    this.showAllApps();
+    var storeCollection = event.context;
+    storeCollection.set('isActive', true);
+    this.target.transitionTo('main.assemblies.collections.details', storeCollection);
+  },
+
+  /**
+   * {{context: App.ServiceGroup}} @param event
+   */
+  makeServiceGroupActive: function(event) {
+    var serviceGroup = event.context;
+    this.set('activeServiceGroupId', serviceGroup.get('id'));
+    this.setActiveServiceGroupId();
+    this.closeNonServiceGroupsPanels();
+    this.target.transitionTo('main.assemblies.serviceGroups.details.summary', serviceGroup);
+  },
+
+  setActiveServiceGroupId: function() {
+    var serviceGroupId = this.get('activeServiceGroupId');
+    var visibleServiceGroups = this.get('visibleServiceGroups');
+    visibleServiceGroups.forEach(function(item) {
+      item.set('isActive', serviceGroupId === item.get('id'));
+    });
+  }.observes('activeServiceGroupId'),
+
+  /**
+   * This method hides DISCOVER->CATEGORIES and MANAGE->COLLECTIONS panels
+   * @private
+   * @method {closeNonServiceGroupsPanels}
+   */
+  closeNonServiceGroupsPanels: function() {
+    var appStoreEl = $("#apps-store");
+    var discoverAssembliesEl = appStoreEl.find("#discover-assemblies-label");
+    var discoverAssembliesContent = appStoreEl.find("#discover-assemblies-content");
+    var collectionsAssembliesEl = appStoreEl.find("#manage-assemblies-collection-label");
+    var collectionsAssembliesContent = appStoreEl.find("#manage-assemblies-collection-content");
+    if (discoverAssembliesContent.hasClass('in')) {
+      discoverAssembliesEl.trigger('click');
+    }
+
+    if (collectionsAssembliesContent.hasClass('in')) {
+      collectionsAssembliesEl.trigger('click');
+    }
+  }
+
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/dashboard.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/dashboard.js b/ambari-web/app/controllers/main/dashboard.js
index 51c09d6..34c207b 100644
--- a/ambari-web/app/controllers/main/dashboard.js
+++ b/ambari-web/app/controllers/main/dashboard.js
@@ -20,5 +20,11 @@ var App = require('app');
 
 App.MainDashboardController = Em.Controller.extend({
   name: 'mainDashboardController',
-  categorySelected: 'widgets'
+  categorySelected: 'widgets',
+  coreServiceGroup: function() {
+    if (!App.router.get('clusterController.isLoaded')) {
+      return {};
+    }
+    return App.ServiceGroup.find().findProperty('serviceGroupName', 'CORE');
+  }.property('App.router.clusterController.isLoaded')
 });
\ No newline at end of file


[04/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/codemirror-min.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/codemirror-min.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/codemirror-min.js
new file mode 100644
index 0000000..13d2b2b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/codemirror-min.js
@@ -0,0 +1,17 @@
+/* CodeMirror - Minified & Bundled
+   Generated on 10/30/2014 with http://codemirror.net/doc/compress.html
+   Version: HEAD
+
+   CodeMirror Library:
+   - codemirror.js
+   Modes:
+   - sql.js
+   Add-ons:
+   - sql-hint.js
+ */
+
+!function(a){if("object"==typeof exports&&"object"==typeof module)module.exports=a();else{if("function"==typeof define&&define.amd)return define([],a);this.CodeMirror=a()}}(function(){"use strict";function w(a,b){if(!(this instanceof w))return new w(a,b);this.options=b=b?Pg(b):{},Pg(ie,b,!1),J(b);var c=b.value;"string"==typeof c&&(c=new Kf(c,b.mode)),this.doc=c;var f=this.display=new x(a,c);f.wrapper.CodeMirror=this,F(this),D(this),b.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),b.autofocus&&!o&&_c(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,focused:!1,suppressEdits:!1,pasteIncoming:!1,cutIncoming:!1,draggingText:!1,highlight:new Fg,keySeq:null},d&&11>e&&setTimeout(Qg($c,this,!0),20),cd(this),hh(),Ac(this),this.curOp.forceUpdate=!0,Of(this,c),b.autofocus&&!o||ah()==f.input?setTimeout(Qg(Hd,this),20):Id(this);for(var g in je)je.hasOwnProperty(g)&&je[g](this,b[g],le);P(this);for(var h=0;h<pe.length;++h)pe[h](this);Cc(this)}function x(a,b){var c
 =this,g=c.input=Xg("textarea",null,null,"position: absolute; padding: 0; width: 1px; height: 1em; outline: none");f?g.style.width="1000px":g.setAttribute("wrap","off"),n&&(g.style.border="1px solid black"),g.setAttribute("autocorrect","off"),g.setAttribute("autocapitalize","off"),g.setAttribute("spellcheck","false"),c.inputDiv=Xg("div",[g],null,"overflow: hidden; position: relative; width: 3px; height: 0px;"),c.scrollbarH=Xg("div",[Xg("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar"),c.scrollbarV=Xg("div",[Xg("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),c.scrollbarFiller=Xg("div",null,"CodeMirror-scrollbar-filler"),c.gutterFiller=Xg("div",null,"CodeMirror-gutter-filler"),c.lineDiv=Xg("div",null,"CodeMirror-code"),c.selectionDiv=Xg("div",null,null,"position: relative; z-index: 1"),c.cursorDiv=Xg("div",null,"CodeMirror-cursors"),c.measure=Xg("div",null,"CodeMirror-measure"),c.lineMeasure=Xg("div",null,"CodeMirror-measure"),c.lineSpace=Xg("div",[
 c.measure,c.lineMeasure,c.selectionDiv,c.cursorDiv,c.lineDiv],null,"position: relative; outline: none"),c.mover=Xg("div",[Xg("div",[c.lineSpace],"CodeMirror-lines")],null,"position: relative"),c.sizer=Xg("div",[c.mover],"CodeMirror-sizer"),c.heightForcer=Xg("div",null,null,"position: absolute; height: "+Ag+"px; width: 1px;"),c.gutters=Xg("div",null,"CodeMirror-gutters"),c.lineGutter=null,c.scroller=Xg("div",[c.sizer,c.heightForcer,c.gutters],"CodeMirror-scroll"),c.scroller.setAttribute("tabIndex","-1"),c.wrapper=Xg("div",[c.inputDiv,c.scrollbarH,c.scrollbarV,c.scrollbarFiller,c.gutterFiller,c.scroller],"CodeMirror"),d&&8>e&&(c.gutters.style.zIndex=-1,c.scroller.style.paddingRight=0),n&&(g.style.width="0px"),f||(c.scroller.draggable=!0),k&&(c.inputDiv.style.height="1px",c.inputDiv.style.position="absolute"),d&&8>e&&(c.scrollbarH.style.minHeight=c.scrollbarV.style.minWidth="18px"),a&&(a.appendChild?a.appendChild(c.wrapper):a(c.wrapper)),c.viewFrom=c.viewTo=b.first,c.view=[],c.external
 Measured=null,c.viewOffset=0,c.lastWrapHeight=c.lastWrapWidth=0,c.updateLineNumbers=null,c.lineNumWidth=c.lineNumInnerWidth=c.lineNumChars=null,c.prevInput="",c.alignWidgets=!1,c.pollingFast=!1,c.poll=new Fg,c.cachedCharWidth=c.cachedTextHeight=c.cachedPaddingH=null,c.inaccurateSelection=!1,c.maxLine=null,c.maxLineLength=0,c.maxLineChanged=!1,c.wheelDX=c.wheelDY=c.wheelStartX=c.wheelStartY=null,c.shift=!1,c.selForContextMenu=null}function y(a){a.doc.mode=w.getMode(a.options,a.doc.modeOption),z(a)}function z(a){a.doc.iter(function(a){a.stateAfter&&(a.stateAfter=null),a.styles&&(a.styles=null)}),a.doc.frontier=a.doc.first,Tb(a,100),a.state.modeGen++,a.curOp&&Pc(a)}function A(a){a.options.lineWrapping?(dh(a.display.wrapper,"CodeMirror-wrap"),a.display.sizer.style.minWidth=""):(ch(a.display.wrapper,"CodeMirror-wrap"),I(a)),C(a),Pc(a),kc(a),setTimeout(function(){M(a)},100)}function B(a){var b=wc(a.display),c=a.options.lineWrapping,d=c&&Math.max(5,a.display.scroller.clientWidth/xc(a.displ
 ay)-3);return function(e){if(ef(a.doc,e))return 0;var f=0;if(e.widgets)for(var g=0;g<e.widgets.length;g++)e.widgets[g].height&&(f+=e.widgets[g].height);return c?f+(Math.ceil(e.text.length/d)||1)*b:f+b}}function C(a){var b=a.doc,c=B(a);b.iter(function(a){var b=c(a);b!=a.height&&Sf(a,b)})}function D(a){a.display.wrapper.className=a.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+a.options.theme.replace(/(^|\s)\s*/g," cm-s-"),kc(a)}function E(a){F(a),Pc(a),setTimeout(function(){O(a)},20)}function F(a){var b=a.display.gutters,c=a.options.gutters;Zg(b);for(var d=0;d<c.length;++d){var e=c[d],f=b.appendChild(Xg("div",null,"CodeMirror-gutter "+e));"CodeMirror-linenumbers"==e&&(a.display.lineGutter=f,f.style.width=(a.display.lineNumWidth||1)+"px")}b.style.display=d?"":"none",G(a)}function G(a){var b=a.display.gutters.offsetWidth;a.display.sizer.style.marginLeft=b+"px",a.display.scrollbarH.style.left=a.options.fixedGutter?b+"px":0}function H(a){if(0==a.height)return 0;for(var c,b=a.text.
 length,d=a;c=Ze(d);){var e=c.find(0,!0);d=e.from.line,b+=e.from.ch-e.to.ch}for(d=a;c=$e(d);){var e=c.find(0,!0);b-=d.text.length-e.from.ch,d=e.to.line,b+=d.text.length-e.to.ch}return b}function I(a){var b=a.display,c=a.doc;b.maxLine=Pf(c,c.first),b.maxLineLength=H(b.maxLine),b.maxLineChanged=!0,c.iter(function(a){var c=H(a);c>b.maxLineLength&&(b.maxLineLength=c,b.maxLine=a)})}function J(a){var b=Mg(a.gutters,"CodeMirror-linenumbers");-1==b&&a.lineNumbers?a.gutters=a.gutters.concat(["CodeMirror-linenumbers"]):b>-1&&!a.lineNumbers&&(a.gutters=a.gutters.slice(0),a.gutters.splice(b,1))}function K(a){return a.display.scroller.clientHeight-a.display.wrapper.clientHeight<Ag-3}function L(a){var b=a.display.scroller;return{clientHeight:b.clientHeight,barHeight:a.display.scrollbarV.clientHeight,scrollWidth:b.scrollWidth,clientWidth:b.clientWidth,hScrollbarTakesSpace:K(a),barWidth:a.display.scrollbarH.clientWidth,docHeight:Math.round(a.doc.height+Yb(a.display))}}function M(a,b){b||(b=L(a));var
  c=a.display,d=lh(c.measure),e=b.docHeight+Ag,f=b.scrollWidth>b.clientWidth;f&&b.scrollWidth<=b.clientWidth+1&&d>0&&!b.hScrollbarTakesSpace&&(f=!1);var g=e>b.clientHeight;if(g?(c.scrollbarV.style.display="block",c.scrollbarV.style.bottom=f?d+"px":"0",c.scrollbarV.firstChild.style.height=Math.max(0,e-b.clientHeight+(b.barHeight||c.scrollbarV.clientHeight))+"px"):(c.scrollbarV.style.display="",c.scrollbarV.firstChild.style.height="0"),f?(c.scrollbarH.style.display="block",c.scrollbarH.style.right=g?d+"px":"0",c.scrollbarH.firstChild.style.width=b.scrollWidth-b.clientWidth+(b.barWidth||c.scrollbarH.clientWidth)+"px"):(c.scrollbarH.style.display="",c.scrollbarH.firstChild.style.width="0"),f&&g?(c.scrollbarFiller.style.display="block",c.scrollbarFiller.style.height=c.scrollbarFiller.style.width=d+"px"):c.scrollbarFiller.style.display="",f&&a.options.coverGutterNextToScrollbar&&a.options.fixedGutter?(c.gutterFiller.style.display="block",c.gutterFiller.style.height=d+"px",c.gutterFiller.st
 yle.width=c.gutters.offsetWidth+"px"):c.gutterFiller.style.display="",!a.state.checkedOverlayScrollbar&&b.clientHeight>0){if(0===d){var h=p&&!l?"12px":"18px";c.scrollbarV.style.minWidth=c.scrollbarH.style.minHeight=h;var i=function(b){og(b)!=c.scrollbarV&&og(b)!=c.scrollbarH&&Kc(a,gd)(b)};qg(c.scrollbarV,"mousedown",i),qg(c.scrollbarH,"mousedown",i)}a.state.checkedOverlayScrollbar=!0}}function N(a,b,c){var d=c&&null!=c.top?Math.max(0,c.top):a.scroller.scrollTop;d=Math.floor(d-Xb(a));var e=c&&null!=c.bottom?c.bottom:d+a.wrapper.clientHeight,f=Uf(b,d),g=Uf(b,e);if(c&&c.ensure){var h=c.ensure.from.line,i=c.ensure.to.line;if(f>h)return{from:h,to:Uf(b,Vf(Pf(b,h))+a.wrapper.clientHeight)};if(Math.min(i,b.lastLine())>=g)return{from:Uf(b,Vf(Pf(b,i))-a.wrapper.clientHeight),to:i}}return{from:f,to:Math.max(g,f+1)}}function O(a){var b=a.display,c=b.view;if(b.alignWidgets||b.gutters.firstChild&&a.options.fixedGutter){for(var d=R(b)-b.scroller.scrollLeft+a.doc.scrollLeft,e=b.gutters.offsetWidth,
 f=d+"px",g=0;g<c.length;g++)if(!c[g].hidden){a.options.fixedGutter&&c[g].gutter&&(c[g].gutter.style.left=f);var h=c[g].alignable;if(h)for(var i=0;i<h.length;i++)h[i].style.left=f}a.options.fixedGutter&&(b.gutters.style.left=d+e+"px")}}function P(a){if(!a.options.lineNumbers)return!1;var b=a.doc,c=Q(a.options,b.first+b.size-1),d=a.display;if(c.length!=d.lineNumChars){var e=d.measure.appendChild(Xg("div",[Xg("div",c)],"CodeMirror-linenumber CodeMirror-gutter-elt")),f=e.firstChild.offsetWidth,g=e.offsetWidth-f;return d.lineGutter.style.width="",d.lineNumInnerWidth=Math.max(f,d.lineGutter.offsetWidth-g),d.lineNumWidth=d.lineNumInnerWidth+g,d.lineNumChars=d.lineNumInnerWidth?c.length:-1,d.lineGutter.style.width=d.lineNumWidth+"px",G(a),!0}return!1}function Q(a,b){return String(a.lineNumberFormatter(b+a.firstLineNumber))}function R(a){return a.scroller.getBoundingClientRect().left-a.sizer.getBoundingClientRect().left}function S(a,b,c){var d=a.display;this.viewport=b,this.visible=N(d,a.doc
 ,b),this.editorIsHidden=!d.wrapper.offsetWidth,this.wrapperHeight=d.wrapper.clientHeight,this.wrapperWidth=d.wrapper.clientWidth,this.oldViewFrom=d.viewFrom,this.oldViewTo=d.viewTo,this.oldScrollerWidth=d.scroller.clientWidth,this.force=c,this.dims=$(a)}function T(a,b){var c=a.display,d=a.doc;if(b.editorIsHidden)return Rc(a),!1;if(!b.force&&b.visible.from>=c.viewFrom&&b.visible.to<=c.viewTo&&(null==c.updateLineNumbers||c.updateLineNumbers>=c.viewTo)&&0==Vc(a))return!1;P(a)&&(Rc(a),b.dims=$(a));var e=d.first+d.size,f=Math.max(b.visible.from-a.options.viewportMargin,d.first),g=Math.min(e,b.visible.to+a.options.viewportMargin);c.viewFrom<f&&f-c.viewFrom<20&&(f=Math.max(d.first,c.viewFrom)),c.viewTo>g&&c.viewTo-g<20&&(g=Math.min(e,c.viewTo)),v&&(f=cf(a.doc,f),g=df(a.doc,g));var h=f!=c.viewFrom||g!=c.viewTo||c.lastWrapHeight!=b.wrapperHeight||c.lastWrapWidth!=b.wrapperWidth;Uc(a,f,g),c.viewOffset=Vf(Pf(a.doc,c.viewFrom)),a.display.mover.style.top=c.viewOffset+"px";var i=Vc(a);if(!h&&0==i
 &&!b.force&&(null==c.updateLineNumbers||c.updateLineNumbers>=c.viewTo))return!1;var j=ah();return i>4&&(c.lineDiv.style.display="none"),_(a,c.updateLineNumbers,b.dims),i>4&&(c.lineDiv.style.display=""),j&&ah()!=j&&j.offsetHeight&&j.focus(),Zg(c.cursorDiv),Zg(c.selectionDiv),h&&(c.lastWrapHeight=b.wrapperHeight,c.lastWrapWidth=b.wrapperWidth,Tb(a,400)),c.updateLineNumbers=null,!0}function U(a,b){for(var c=b.force,d=b.viewport,e=!0;;e=!1){if(e&&a.options.lineWrapping&&b.oldScrollerWidth!=a.display.scroller.clientWidth)c=!0;else if(c=!1,d&&null!=d.top&&(d={top:Math.min(a.doc.height+Yb(a.display)-Ag-a.display.scroller.clientHeight,d.top)}),b.visible=N(a.display,a.doc,d),b.visible.from>=a.display.viewFrom&&b.visible.to<=a.display.viewTo)break;if(!T(a,b))break;Y(a);var f=L(a);Pb(a),W(a,f),M(a,f)}ug(a,"update",a),(a.display.viewFrom!=b.oldViewFrom||a.display.viewTo!=b.oldViewTo)&&ug(a,"viewportChange",a,a.display.viewFrom,a.display.viewTo)}function V(a,b){var c=new S(a,b);if(T(a,c)){Y(a),U
 (a,c);var d=L(a);Pb(a),W(a,d),M(a,d)}}function W(a,b){a.display.sizer.style.minHeight=a.display.heightForcer.style.top=b.docHeight+"px",a.display.gutters.style.height=Math.max(b.docHeight,b.clientHeight-Ag)+"px"}function X(a,b){a.display.sizer.offsetWidth+a.display.gutters.offsetWidth<a.display.scroller.clientWidth-1&&(a.display.sizer.style.minHeight=a.display.heightForcer.style.top="0px",a.display.gutters.style.height=b.docHeight+"px")}function Y(a){for(var b=a.display,c=b.lineDiv.offsetTop,f=0;f<b.view.length;f++){var h,g=b.view[f];if(!g.hidden){if(d&&8>e){var i=g.node.offsetTop+g.node.offsetHeight;h=i-c,c=i}else{var j=g.node.getBoundingClientRect();h=j.bottom-j.top}var k=g.line.height-h;if(2>h&&(h=wc(b)),(k>.001||-.001>k)&&(Sf(g.line,h),Z(g.line),g.rest))for(var l=0;l<g.rest.length;l++)Z(g.rest[l])}}}function Z(a){if(a.widgets)for(var b=0;b<a.widgets.length;++b)a.widgets[b].height=a.widgets[b].node.offsetHeight}function $(a){for(var b=a.display,c={},d={},e=b.gutters.clientLeft,f=
 b.gutters.firstChild,g=0;f;f=f.nextSibling,++g)c[a.options.gutters[g]]=f.offsetLeft+f.clientLeft+e,d[a.options.gutters[g]]=f.clientWidth;return{fixedPos:R(b),gutterTotalWidth:b.gutters.offsetWidth,gutterLeft:c,gutterWidth:d,wrapperWidth:b.wrapper.clientWidth}}function _(a,b,c){function i(b){var c=b.nextSibling;return f&&p&&a.display.currentWheelTarget==b?b.style.display="none":b.parentNode.removeChild(b),c}for(var d=a.display,e=a.options.lineNumbers,g=d.lineDiv,h=g.firstChild,j=d.view,k=d.viewFrom,l=0;l<j.length;l++){var m=j[l];if(m.hidden);else if(m.node){for(;h!=m.node;)h=i(h);var o=e&&null!=b&&k>=b&&m.lineNumber;m.changes&&(Mg(m.changes,"gutter")>-1&&(o=!1),ab(a,m,k,c)),o&&(Zg(m.lineNumber),m.lineNumber.appendChild(document.createTextNode(Q(a.options,k)))),h=m.node.nextSibling}else{var n=ib(a,m,k,c);g.insertBefore(n,h)}k+=m.size}for(;h;)h=i(h)}function ab(a,b,c,d){for(var e=0;e<b.changes.length;e++){var f=b.changes[e];"text"==f?eb(a,b):"gutter"==f?gb(a,b,c,d):"class"==f?fb(b):"wi
 dget"==f&&hb(b,d)}b.changes=null}function bb(a){return a.node==a.text&&(a.node=Xg("div",null,null,"position: relative"),a.text.parentNode&&a.text.parentNode.replaceChild(a.node,a.text),a.node.appendChild(a.text),d&&8>e&&(a.node.style.zIndex=2)),a.node}function cb(a){var b=a.bgClass?a.bgClass+" "+(a.line.bgClass||""):a.line.bgClass;if(b&&(b+=" CodeMirror-linebackground"),a.background)b?a.background.className=b:(a.background.parentNode.removeChild(a.background),a.background=null);else if(b){var c=bb(a);a.background=c.insertBefore(Xg("div",null,b),c.firstChild)}}function db(a,b){var c=a.display.externalMeasured;return c&&c.line==b.line?(a.display.externalMeasured=null,b.measure=c.measure,c.built):yf(a,b)}function eb(a,b){var c=b.text.className,d=db(a,b);b.text==b.node&&(b.node=d.pre),b.text.parentNode.replaceChild(d.pre,b.text),b.text=d.pre,d.bgClass!=b.bgClass||d.textClass!=b.textClass?(b.bgClass=d.bgClass,b.textClass=d.textClass,fb(b)):c&&(b.text.className=c)}function fb(a){cb(a),a.l
 ine.wrapClass?bb(a).className=a.line.wrapClass:a.node!=a.text&&(a.node.className="");var b=a.textClass?a.textClass+" "+(a.line.textClass||""):a.line.textClass;a.text.className=b||""}function gb(a,b,c,d){b.gutter&&(b.node.removeChild(b.gutter),b.gutter=null);var e=b.line.gutterMarkers;if(a.options.lineNumbers||e){var f=bb(b),g=b.gutter=f.insertBefore(Xg("div",null,"CodeMirror-gutter-wrapper","position: absolute; left: "+(a.options.fixedGutter?d.fixedPos:-d.gutterTotalWidth)+"px"),b.text);if(!a.options.lineNumbers||e&&e["CodeMirror-linenumbers"]||(b.lineNumber=g.appendChild(Xg("div",Q(a.options,c),"CodeMirror-linenumber CodeMirror-gutter-elt","left: "+d.gutterLeft["CodeMirror-linenumbers"]+"px; width: "+a.display.lineNumInnerWidth+"px"))),e)for(var h=0;h<a.options.gutters.length;++h){var i=a.options.gutters[h],j=e.hasOwnProperty(i)&&e[i];j&&g.appendChild(Xg("div",[j],"CodeMirror-gutter-elt","left: "+d.gutterLeft[i]+"px; width: "+d.gutterWidth[i]+"px"))}}}function hb(a,b){a.alignable&&
 (a.alignable=null);for(var d,c=a.node.firstChild;c;c=d){var d=c.nextSibling;"CodeMirror-linewidget"==c.className&&a.node.removeChild(c)}jb(a,b)}function ib(a,b,c,d){var e=db(a,b);return b.text=b.node=e.pre,e.bgClass&&(b.bgClass=e.bgClass),e.textClass&&(b.textClass=e.textClass),fb(b),gb(a,b,c,d),jb(b,d),b.node}function jb(a,b){if(kb(a.line,a,b,!0),a.rest)for(var c=0;c<a.rest.length;c++)kb(a.rest[c],a,b,!1)}function kb(a,b,c,d){if(a.widgets)for(var e=bb(b),f=0,g=a.widgets;f<g.length;++f){var h=g[f],i=Xg("div",[h.node],"CodeMirror-linewidget");h.handleMouseEvents||(i.ignoreEvents=!0),lb(h,i,b,c),d&&h.above?e.insertBefore(i,b.gutter||b.text):e.appendChild(i),ug(h,"redraw")}}function lb(a,b,c,d){if(a.noHScroll){(c.alignable||(c.alignable=[])).push(b);var e=d.wrapperWidth;b.style.left=d.fixedPos+"px",a.coverGutter||(e-=d.gutterTotalWidth,b.style.paddingLeft=d.gutterTotalWidth+"px"),b.style.width=e+"px"}a.coverGutter&&(b.style.zIndex=5,b.style.position="relative",a.noHScroll||(b.style.marg
 inLeft=-d.gutterTotalWidth+"px"))}function ob(a){return mb(a.line,a.ch)}function pb(a,b){return nb(a,b)<0?b:a}function qb(a,b){return nb(a,b)<0?a:b}function rb(a,b){this.ranges=a,this.primIndex=b}function sb(a,b){this.anchor=a,this.head=b}function tb(a,b){var c=a[b];a.sort(function(a,b){return nb(a.from(),b.from())}),b=Mg(a,c);for(var d=1;d<a.length;d++){var e=a[d],f=a[d-1];if(nb(f.to(),e.from())>=0){var g=qb(f.from(),e.from()),h=pb(f.to(),e.to()),i=f.empty()?e.from()==e.head:f.from()==f.head;b>=d&&--b,a.splice(--d,2,new sb(i?h:g,i?g:h))}}return new rb(a,b)}function ub(a,b){return new rb([new sb(a,b||a)],0)}function vb(a,b){return Math.max(a.first,Math.min(b,a.first+a.size-1))}function wb(a,b){if(b.line<a.first)return mb(a.first,0);var c=a.first+a.size-1;return b.line>c?mb(c,Pf(a,c).text.length):xb(b,Pf(a,b.line).text.length)}function xb(a,b){var c=a.ch;return null==c||c>b?mb(a.line,b):0>c?mb(a.line,0):a}function yb(a,b){return b>=a.first&&b<a.first+a.size}function zb(a,b){for(var c
 =[],d=0;d<b.length;d++)c[d]=wb(a,b[d]);return c}function Ab(a,b,c,d){if(a.cm&&a.cm.display.shift||a.extend){var e=b.anchor;if(d){var f=nb(c,e)<0;f!=nb(d,e)<0?(e=c,c=d):f!=nb(c,d)<0&&(c=d)}return new sb(e,c)}return new sb(d||c,c)}function Bb(a,b,c,d){Hb(a,new rb([Ab(a,a.sel.primary(),b,c)],0),d)}function Cb(a,b,c){for(var d=[],e=0;e<a.sel.ranges.length;e++)d[e]=Ab(a,a.sel.ranges[e],b[e],null);var f=tb(d,a.sel.primIndex);Hb(a,f,c)}function Db(a,b,c,d){var e=a.sel.ranges.slice(0);e[b]=c,Hb(a,tb(e,a.sel.primIndex),d)}function Eb(a,b,c,d){Hb(a,ub(b,c),d)}function Fb(a,b){var c={ranges:b.ranges,update:function(b){this.ranges=[];for(var c=0;c<b.length;c++)this.ranges[c]=new sb(wb(a,b[c].anchor),wb(a,b[c].head))}};return sg(a,"beforeSelectionChange",a,c),a.cm&&sg(a.cm,"beforeSelectionChange",a.cm,c),c.ranges!=b.ranges?tb(c.ranges,c.ranges.length-1):b}function Gb(a,b,c){var d=a.history.done,e=Kg(d);e&&e.ranges?(d[d.length-1]=b,Ib(a,b,c)):Hb(a,b,c)}function Hb(a,b,c){Ib(a,b,c),bg(a,a.sel,a.cm
 ?a.cm.curOp.id:0/0,c)}function Ib(a,b,c){(yg(a,"beforeSelectionChange")||a.cm&&yg(a.cm,"beforeSelectionChange"))&&(b=Fb(a,b));var d=c&&c.bias||(nb(b.primary().head,a.sel.primary().head)<0?-1:1);Jb(a,Lb(a,b,d,!0)),c&&c.scroll===!1||!a.cm||be(a.cm)}function Jb(a,b){b.equals(a.sel)||(a.sel=b,a.cm&&(a.cm.curOp.updateInput=a.cm.curOp.selectionChanged=!0,xg(a.cm)),ug(a,"cursorActivity",a))}function Kb(a){Jb(a,Lb(a,a.sel,null,!1),Cg)}function Lb(a,b,c,d){for(var e,f=0;f<b.ranges.length;f++){var g=b.ranges[f],h=Mb(a,g.anchor,c,d),i=Mb(a,g.head,c,d);(e||h!=g.anchor||i!=g.head)&&(e||(e=b.ranges.slice(0,f)),e[f]=new sb(h,i))}return e?tb(e,b.primIndex):b}function Mb(a,b,c,d){var e=!1,f=b,g=c||1;a.cantEdit=!1;a:for(;;){var h=Pf(a,f.line);if(h.markedSpans)for(var i=0;i<h.markedSpans.length;++i){var j=h.markedSpans[i],k=j.marker;if((null==j.from||(k.inclusiveLeft?j.from<=f.ch:j.from<f.ch))&&(null==j.to||(k.inclusiveRight?j.to>=f.ch:j.to>f.ch))){if(d&&(sg(k,"beforeCursorEnter"),k.explicitlyCleared)
 ){if(h.markedSpans){--i;continue}break}if(!k.atomic)continue;var l=k.find(0>g?-1:1);if(0==nb(l,f)&&(l.ch+=g,l.ch<0?l=l.line>a.first?wb(a,mb(l.line-1)):null:l.ch>h.text.length&&(l=l.line<a.first+a.size-1?mb(l.line+1,0):null),!l)){if(e)return d?(a.cantEdit=!0,mb(a.first,0)):Mb(a,b,c,!0);e=!0,l=b,g=-g}f=l;continue a}}return f}}function Nb(a){for(var b=a.display,c=a.doc,d={},e=d.cursors=document.createDocumentFragment(),f=d.selection=document.createDocumentFragment(),g=0;g<c.sel.ranges.length;g++){var h=c.sel.ranges[g],i=h.empty();(i||a.options.showCursorWhenSelecting)&&Qb(a,h,e),i||Rb(a,h,f)}if(a.options.moveInputWithCursor){var j=qc(a,c.sel.primary().head,"div"),k=b.wrapper.getBoundingClientRect(),l=b.lineDiv.getBoundingClientRect();d.teTop=Math.max(0,Math.min(b.wrapper.clientHeight-10,j.top+l.top-k.top)),d.teLeft=Math.max(0,Math.min(b.wrapper.clientWidth-10,j.left+l.left-k.left))}return d}function Ob(a,b){$g(a.display.cursorDiv,b.cursors),$g(a.display.selectionDiv,b.selection),null!=
 b.teTop&&(a.display.inputDiv.style.top=b.teTop+"px",a.display.inputDiv.style.left=b.teLeft+"px")}function Pb(a){Ob(a,Nb(a))}function Qb(a,b,c){var d=qc(a,b.head,"div",null,null,!a.options.singleCursorHeightPerLine),e=c.appendChild(Xg("div","\xa0","CodeMirror-cursor"));if(e.style.left=d.left+"px",e.style.top=d.top+"px",e.style.height=Math.max(0,d.bottom-d.top)*a.options.cursorHeight+"px",d.other){var f=c.appendChild(Xg("div","\xa0","CodeMirror-cursor CodeMirror-secondarycursor"));f.style.display="",f.style.left=d.other.left+"px",f.style.top=d.other.top+"px",f.style.height=.85*(d.other.bottom-d.other.top)+"px"}}function Rb(a,b,c){function j(a,b,c,d){0>b&&(b=0),b=Math.round(b),d=Math.round(d),f.appendChild(Xg("div",null,"CodeMirror-selected","position: absolute; left: "+a+"px; top: "+b+"px; width: "+(null==c?i-a:c)+"px; height: "+(d-b)+"px"))}function k(b,c,d){function m(c,d){return pc(a,mb(b,c),"div",f,d)}var k,l,f=Pf(e,b),g=f.text.length;return wh(Wf(f),c||0,null==d?g:d,function(a,b,
 e){var n,o,p,f=m(a,"left");if(a==b)n=f,o=p=f.left;else{if(n=m(b-1,"right"),"rtl"==e){var q=f;f=n,n=q}o=f.left,p=n.right}null==c&&0==a&&(o=h),n.top-f.top>3&&(j(o,f.top,null,f.bottom),o=h,f.bottom<n.top&&j(o,f.bottom,null,n.top)),null==d&&b==g&&(p=i),(!k||f.top<k.top||f.top==k.top&&f.left<k.left)&&(k=f),(!l||n.bottom>l.bottom||n.bottom==l.bottom&&n.right>l.right)&&(l=n),h+1>o&&(o=h),j(o,n.top,p-o,n.bottom)}),{start:k,end:l}}var d=a.display,e=a.doc,f=document.createDocumentFragment(),g=Zb(a.display),h=g.left,i=d.lineSpace.offsetWidth-g.right,l=b.from(),m=b.to();if(l.line==m.line)k(l.line,l.ch,m.ch);else{var n=Pf(e,l.line),o=Pf(e,m.line),p=af(n)==af(o),q=k(l.line,l.ch,p?n.text.length+1:null).end,r=k(m.line,p?0:null,m.ch).start;p&&(q.top<r.top-2?(j(q.right,q.top,null,q.bottom),j(h,r.top,r.left,r.bottom)):j(q.right,q.top,r.left-q.right,q.bottom)),q.bottom<r.top&&j(h,q.bottom,null,r.top)}c.appendChild(f)}function Sb(a){if(a.state.focused){var b=a.display;clearInterval(b.blinker);var c=!0;b
 .cursorDiv.style.visibility="",a.options.cursorBlinkRate>0?b.blinker=setInterval(function(){b.cursorDiv.style.visibility=(c=!c)?"":"hidden"},a.options.cursorBlinkRate):a.options.cursorBlinkRate<0&&(b.cursorDiv.style.visibility="hidden")}}function Tb(a,b){a.doc.mode.startState&&a.doc.frontier<a.display.viewTo&&a.state.highlight.set(b,Qg(Ub,a))}function Ub(a){var b=a.doc;if(b.frontier<b.first&&(b.frontier=b.first),!(b.frontier>=a.display.viewTo)){var c=+new Date+a.options.workTime,d=re(b.mode,Wb(a,b.frontier)),e=[];b.iter(b.frontier,Math.min(b.first+b.size,a.display.viewTo+500),function(f){if(b.frontier>=a.display.viewFrom){var g=f.styles,h=sf(a,f,d,!0);f.styles=h.styles;var i=f.styleClasses,j=h.classes;j?f.styleClasses=j:i&&(f.styleClasses=null);for(var k=!g||g.length!=f.styles.length||i!=j&&(!i||!j||i.bgClass!=j.bgClass||i.textClass!=j.textClass),l=0;!k&&l<g.length;++l)k=g[l]!=f.styles[l];k&&e.push(b.frontier),f.stateAfter=re(b.mode,d)}else uf(a,f.text,d),f.stateAfter=0==b.frontier%
 5?re(b.mode,d):null;return++b.frontier,+new Date>c?(Tb(a,a.options.workDelay),!0):void 0}),e.length&&Jc(a,function(){for(var b=0;b<e.length;b++)Qc(a,e[b],"text")})}}function Vb(a,b,c){for(var d,e,f=a.doc,g=c?-1:b-(a.doc.mode.innerMode?1e3:100),h=b;h>g;--h){if(h<=f.first)return f.first;var i=Pf(f,h-1);if(i.stateAfter&&(!c||h<=f.frontier))return h;var j=Gg(i.text,null,a.options.tabSize);(null==e||d>j)&&(e=h-1,d=j)}return e}function Wb(a,b,c){var d=a.doc,e=a.display;if(!d.mode.startState)return!0;var f=Vb(a,b,c),g=f>d.first&&Pf(d,f-1).stateAfter;return g=g?re(d.mode,g):se(d.mode),d.iter(f,b,function(c){uf(a,c.text,g);var h=f==b-1||0==f%5||f>=e.viewFrom&&f<e.viewTo;c.stateAfter=h?re(d.mode,g):null,++f}),c&&(d.frontier=f),g}function Xb(a){return a.lineSpace.offsetTop}function Yb(a){return a.mover.offsetHeight-a.lineSpace.offsetHeight}function Zb(a){if(a.cachedPaddingH)return a.cachedPaddingH;var b=$g(a.measure,Xg("pre","x")),c=window.getComputedStyle?window.getComputedStyle(b):b.currentS
 tyle,d={left:parseInt(c.paddingLeft),right:parseInt(c.paddingRight)};return isNaN(d.left)||isNaN(d.right)||(a.cachedPaddingH=d),d}function $b(a,b,c){var d=a.options.lineWrapping,e=d&&a.display.scroller.clientWidth;if(!b.measure.heights||d&&b.measure.width!=e){var f=b.measure.heights=[];if(d){b.measure.width=e;for(var g=b.text.firstChild.getClientRects(),h=0;h<g.length-1;h++){var i=g[h],j=g[h+1];Math.abs(i.bottom-j.bottom)>2&&f.push((i.bottom+j.top)/2-c.top)}}f.push(c.bottom-c.top)}}function _b(a,b,c){if(a.line==b)return{map:a.measure.map,cache:a.measure.cache};for(var d=0;d<a.rest.length;d++)if(a.rest[d]==b)return{map:a.measure.maps[d],cache:a.measure.caches[d]};for(var d=0;d<a.rest.length;d++)if(Tf(a.rest[d])>c)return{map:a.measure.maps[d],cache:a.measure.caches[d],before:!0}}function ac(a,b){b=af(b);var c=Tf(b),d=a.display.externalMeasured=new Nc(a.doc,b,c);d.lineN=c;var e=d.built=yf(a,d);return d.text=e.pre,$g(a.display.lineMeasure,e.pre),d}function bc(a,b,c,d){return ec(a,dc(a,b
 ),c,d)}function cc(a,b){if(b>=a.display.viewFrom&&b<a.display.viewTo)return a.display.view[Sc(a,b)];var c=a.display.externalMeasured;return c&&b>=c.lineN&&b<c.lineN+c.size?c:void 0}function dc(a,b){var c=Tf(b),d=cc(a,c);d&&!d.text?d=null:d&&d.changes&&ab(a,d,c,$(a)),d||(d=ac(a,b));var e=_b(d,b,c);return{line:b,view:d,rect:null,map:e.map,cache:e.cache,before:e.before,hasHeights:!1}}function ec(a,b,c,d,e){b.before&&(c=-1);var g,f=c+(d||"");return b.cache.hasOwnProperty(f)?g=b.cache[f]:(b.rect||(b.rect=b.view.text.getBoundingClientRect()),b.hasHeights||($b(a,b.view,b.rect),b.hasHeights=!0),g=gc(a,b,c,d),g.bogus||(b.cache[f]=g)),{left:g.left,right:g.right,top:e?g.rtop:g.top,bottom:e?g.rbottom:g.bottom}}function gc(a,b,c,f){for(var h,i,j,k,g=b.map,l=0;l<g.length;l+=3){var m=g[l],n=g[l+1];if(m>c?(i=0,j=1,k="left"):n>c?(i=c-m,j=i+1):(l==g.length-3||c==n&&g[l+3]>c)&&(j=n-m,i=j-1,c>=n&&(k="right")),null!=i){if(h=g[l+2],m==n&&f==(h.insertLeft?"left":"right")&&(k=f),"left"==f&&0==i)for(;l&&g[l
 -2]==g[l-3]&&g[l-1].insertLeft;)h=g[(l-=3)+2],k="left";if("right"==f&&i==n-m)for(;l<g.length-3&&g[l+3]==g[l+4]&&!g[l+5].insertLeft;)h=g[(l+=3)+2],k="right";break}}var o;if(3==h.nodeType){for(var l=0;4>l;l++){for(;i&&Wg(b.line.text.charAt(m+i));)--i;for(;n>m+j&&Wg(b.line.text.charAt(m+j));)++j;if(d&&9>e&&0==i&&j==n-m)o=h.parentNode.getBoundingClientRect();else if(d&&a.options.lineWrapping){var p=Yg(h,i,j).getClientRects();o=p.length?p["right"==f?p.length-1:0]:fc}else o=Yg(h,i,j).getBoundingClientRect()||fc;if(o.left||o.right||0==i)break;j=i,i-=1,k="right"}d&&11>e&&(o=hc(a.display.measure,o))}else{i>0&&(k=f="right");var p;o=a.options.lineWrapping&&(p=h.getClientRects()).length>1?p["right"==f?p.length-1:0]:h.getBoundingClientRect()}if(d&&9>e&&!i&&(!o||!o.left&&!o.right)){var q=h.parentNode.getClientRects()[0];o=q?{left:q.left,right:q.left+xc(a.display),top:q.top,bottom:q.bottom}:fc}for(var r=o.top-b.rect.top,s=o.bottom-b.rect.top,t=(r+s)/2,u=b.view.measure.heights,l=0;l<u.length-1&&!(t
 <u[l]);l++);var v=l?u[l-1]:0,w=u[l],x={left:("right"==k?o.right:o.left)-b.rect.left,right:("left"==k?o.left:o.right)-b.rect.left,top:v,bottom:w};return o.left||o.right||(x.bogus=!0),a.options.singleCursorHeightPerLine||(x.rtop=r,x.rbottom=s),x}function hc(a,b){if(!window.screen||null==screen.logicalXDPI||screen.logicalXDPI==screen.deviceXDPI||!uh(a))return b;var c=screen.logicalXDPI/screen.deviceXDPI,d=screen.logicalYDPI/screen.deviceYDPI;return{left:b.left*c,right:b.right*c,top:b.top*d,bottom:b.bottom*d}}function ic(a){if(a.measure&&(a.measure.cache={},a.measure.heights=null,a.rest))for(var b=0;b<a.rest.length;b++)a.measure.caches[b]={}}function jc(a){a.display.externalMeasure=null,Zg(a.display.lineMeasure);for(var b=0;b<a.display.view.length;b++)ic(a.display.view[b])}function kc(a){jc(a),a.display.cachedCharWidth=a.display.cachedTextHeight=a.display.cachedPaddingH=null,a.options.lineWrapping||(a.display.maxLineChanged=!0),a.display.lineNumChars=null}function lc(){return window.pag
 eXOffset||(document.documentElement||document.body).scrollLeft}function mc(){return window.pageYOffset||(document.documentElement||document.body).scrollTop}function nc(a,b,c,d){if(b.widgets)for(var e=0;e<b.widgets.length;++e)if(b.widgets[e].above){var f=jf(b.widgets[e]);c.top+=f,c.bottom+=f}if("line"==d)return c;d||(d="local");var g=Vf(b);if("local"==d?g+=Xb(a.display):g-=a.display.viewOffset,"page"==d||"window"==d){var h=a.display.lineSpace.getBoundingClientRect();g+=h.top+("window"==d?0:mc());var i=h.left+("window"==d?0:lc());c.left+=i,c.right+=i}return c.top+=g,c.bottom+=g,c}function oc(a,b,c){if("div"==c)return b;var d=b.left,e=b.top;if("page"==c)d-=lc(),e-=mc();else if("local"==c||!c){var f=a.display.sizer.getBoundingClientRect();d+=f.left,e+=f.top}var g=a.display.lineSpace.getBoundingClientRect();return{left:d-g.left,top:e-g.top}}function pc(a,b,c,d,e){return d||(d=Pf(a.doc,b.line)),nc(a,d,bc(a,d,b.ch,e),c)}function qc(a,b,c,d,e,f){function g(b,g){var h=ec(a,e,b,g?"right":"lef
 t",f);return g?h.left=h.right:h.right=h.left,nc(a,d,h,c)}function h(a,b){var c=i[b],d=c.level%2;return a==xh(c)&&b&&c.level<i[b-1].level?(c=i[--b],a=yh(c)-(c.level%2?0:1),d=!0):a==yh(c)&&b<i.length-1&&c.level<i[b+1].level&&(c=i[++b],a=xh(c)-c.level%2,d=!1),d&&a==c.to&&a>c.from?g(a-1):g(a,d)}d=d||Pf(a.doc,b.line),e||(e=dc(a,d));var i=Wf(d),j=b.ch;if(!i)return g(j);var k=Gh(i,j),l=h(j,k);return null!=Fh&&(l.other=h(j,Fh)),l}function rc(a,b){var c=0,b=wb(a.doc,b);a.options.lineWrapping||(c=xc(a.display)*b.ch);var d=Pf(a.doc,b.line),e=Vf(d)+Xb(a.display);return{left:c,right:c,top:e,bottom:e+d.height}}function sc(a,b,c,d){var e=mb(a,b);return e.xRel=d,c&&(e.outside=!0),e}function tc(a,b,c){var d=a.doc;if(c+=a.display.viewOffset,0>c)return sc(d.first,0,!0,-1);var e=Uf(d,c),f=d.first+d.size-1;if(e>f)return sc(d.first+d.size-1,Pf(d,f).text.length,!0,1);0>b&&(b=0);for(var g=Pf(d,e);;){var h=uc(a,g,e,b,c),i=$e(g),j=i&&i.find(0,!0);if(!i||!(h.ch>j.from.ch||h.ch==j.from.ch&&h.xRel>0))return h;e
 =Tf(g=j.to.line)}}function uc(a,b,c,d,e){function j(d){var e=qc(a,mb(c,d),"line",b,i);return g=!0,f>e.bottom?e.left-h:f<e.top?e.left+h:(g=!1,e.left)}var f=e-Vf(b),g=!1,h=2*a.display.wrapper.clientWidth,i=dc(a,b),k=Wf(b),l=b.text.length,m=zh(b),n=Ah(b),o=j(m),p=g,q=j(n),r=g;if(d>q)return sc(c,n,r,1);for(;;){if(k?n==m||n==Ih(b,m,1):1>=n-m){for(var s=o>d||q-d>=d-o?m:n,t=d-(s==m?o:q);Wg(b.text.charAt(s));)++s;var u=sc(c,s,s==m?p:r,-1>t?-1:t>1?1:0);return u}var v=Math.ceil(l/2),w=m+v;if(k){w=m;for(var x=0;v>x;++x)w=Ih(b,w,1)}var y=j(w);y>d?(n=w,q=y,(r=g)&&(q+=1e3),l=v):(m=w,o=y,p=g,l-=v)}}function wc(a){if(null!=a.cachedTextHeight)return a.cachedTextHeight;if(null==vc){vc=Xg("pre");for(var b=0;49>b;++b)vc.appendChild(document.createTextNode("x")),vc.appendChild(Xg("br"));vc.appendChild(document.createTextNode("x"))}$g(a.measure,vc);var c=vc.offsetHeight/50;return c>3&&(a.cachedTextHeight=c),Zg(a.measure),c||1}function xc(a){if(null!=a.cachedCharWidth)return a.cachedCharWidth;var b=Xg("sp
 an","xxxxxxxxxx"),c=Xg("pre",[b]);$g(a.measure,c);var d=b.getBoundingClientRect(),e=(d.right-d.left)/10;return e>2&&(a.cachedCharWidth=e),e||10}function Ac(a){a.curOp={cm:a,viewChanged:!1,startHeight:a.doc.height,forceUpdate:!1,updateInput:null,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,id:++zc},yc?yc.ops.push(a.curOp):a.curOp.ownsGroup=yc={ops:[a.curOp],delayedCallbacks:[]}}function Bc(a){var b=a.delayedCallbacks,c=0;do{for(;c<b.length;c++)b[c]();for(var d=0;d<a.ops.length;d++){var e=a.ops[d];if(e.cursorActivityHandlers)for(;e.cursorActivityCalled<e.cursorActivityHandlers.length;)e.cursorActivityHandlers[e.cursorActivityCalled++](e.cm)}}while(c<b.length)}function Cc(a){var b=a.curOp,c=b.ownsGroup;if(c)try{Bc(c)}finally{yc=null;for(var d=0;d<c.ops.length;d++)c.ops[d].cm.curOp=null;Dc(c)}}function Dc(a){for(var b=a.ops,c=0;c<b.length;c++)Ec(b[c]);for(var c=0;c<b.leng
 th;c++)Fc(b[c]);for(var c=0;c<b.length;c++)Gc(b[c]);for(var c=0;c<b.length;c++)Hc(b[c]);for(var c=0;c<b.length;c++)Ic(b[c])
+}function Ec(a){var b=a.cm,c=b.display;a.updateMaxLine&&I(b),a.mustUpdate=a.viewChanged||a.forceUpdate||null!=a.scrollTop||a.scrollToPos&&(a.scrollToPos.from.line<c.viewFrom||a.scrollToPos.to.line>=c.viewTo)||c.maxLineChanged&&b.options.lineWrapping,a.update=a.mustUpdate&&new S(b,a.mustUpdate&&{top:a.scrollTop,ensure:a.scrollToPos},a.forceUpdate)}function Fc(a){a.updatedDisplay=a.mustUpdate&&T(a.cm,a.update)}function Gc(a){var b=a.cm,c=b.display;a.updatedDisplay&&Y(b),a.barMeasure=L(b),c.maxLineChanged&&!b.options.lineWrapping&&(a.adjustWidthTo=bc(b,c.maxLine,c.maxLine.text.length).left+3,a.maxScrollLeft=Math.max(0,c.sizer.offsetLeft+a.adjustWidthTo+Ag-c.scroller.clientWidth)),(a.updatedDisplay||a.selectionChanged)&&(a.newSelectionNodes=Nb(b))}function Hc(a){var b=a.cm;null!=a.adjustWidthTo&&(b.display.sizer.style.minWidth=a.adjustWidthTo+"px",a.maxScrollLeft<b.doc.scrollLeft&&sd(b,Math.min(b.display.scroller.scrollLeft,a.maxScrollLeft),!0),b.display.maxLineChanged=!1),a.newSelectio
 nNodes&&Ob(b,a.newSelectionNodes),a.updatedDisplay&&W(b,a.barMeasure),(a.updatedDisplay||a.startHeight!=b.doc.height)&&M(b,a.barMeasure),a.selectionChanged&&Sb(b),b.state.focused&&a.updateInput&&$c(b,a.typing)}function Ic(a){var b=a.cm,c=b.display,d=b.doc;if(null!=a.adjustWidthTo&&Math.abs(a.barMeasure.scrollWidth-b.display.scroller.scrollWidth)>1&&M(b),a.updatedDisplay&&U(b,a.update),null==c.wheelStartX||null==a.scrollTop&&null==a.scrollLeft&&!a.scrollToPos||(c.wheelStartX=c.wheelStartY=null),null!=a.scrollTop&&(c.scroller.scrollTop!=a.scrollTop||a.forceScroll)){var e=Math.max(0,Math.min(c.scroller.scrollHeight-c.scroller.clientHeight,a.scrollTop));c.scroller.scrollTop=c.scrollbarV.scrollTop=d.scrollTop=e}if(null!=a.scrollLeft&&(c.scroller.scrollLeft!=a.scrollLeft||a.forceScroll)){var g=Math.max(0,Math.min(c.scroller.scrollWidth-c.scroller.clientWidth,a.scrollLeft));c.scroller.scrollLeft=c.scrollbarH.scrollLeft=d.scrollLeft=g,O(b)}if(a.scrollToPos){var h=Zd(b,wb(d,a.scrollToPos.fro
 m),wb(d,a.scrollToPos.to),a.scrollToPos.margin);a.scrollToPos.isCursor&&b.state.focused&&Yd(b,h)}var i=a.maybeHiddenMarkers,j=a.maybeUnhiddenMarkers;if(i)for(var k=0;k<i.length;++k)i[k].lines.length||sg(i[k],"hide");if(j)for(var k=0;k<j.length;++k)j[k].lines.length&&sg(j[k],"unhide");c.wrapper.offsetHeight&&(d.scrollTop=b.display.scroller.scrollTop),a.updatedDisplay&&f&&(b.options.lineWrapping&&X(b,a.barMeasure),a.barMeasure.scrollWidth>a.barMeasure.clientWidth&&a.barMeasure.scrollWidth<a.barMeasure.clientWidth+1&&!K(b)&&M(b)),a.changeObjs&&sg(b,"changes",b,a.changeObjs)}function Jc(a,b){if(a.curOp)return b();Ac(a);try{return b()}finally{Cc(a)}}function Kc(a,b){return function(){if(a.curOp)return b.apply(a,arguments);Ac(a);try{return b.apply(a,arguments)}finally{Cc(a)}}}function Lc(a){return function(){if(this.curOp)return a.apply(this,arguments);Ac(this);try{return a.apply(this,arguments)}finally{Cc(this)}}}function Mc(a){return function(){var b=this.cm;if(!b||b.curOp)return a.appl
 y(this,arguments);Ac(b);try{return a.apply(this,arguments)}finally{Cc(b)}}}function Nc(a,b,c){this.line=b,this.rest=bf(b),this.size=this.rest?Tf(Kg(this.rest))-c+1:1,this.node=this.text=null,this.hidden=ef(a,b)}function Oc(a,b,c){for(var e,d=[],f=b;c>f;f=e){var g=new Nc(a.doc,Pf(a.doc,f),f);e=f+g.size,d.push(g)}return d}function Pc(a,b,c,d){null==b&&(b=a.doc.first),null==c&&(c=a.doc.first+a.doc.size),d||(d=0);var e=a.display;if(d&&c<e.viewTo&&(null==e.updateLineNumbers||e.updateLineNumbers>b)&&(e.updateLineNumbers=b),a.curOp.viewChanged=!0,b>=e.viewTo)v&&cf(a.doc,b)<e.viewTo&&Rc(a);else if(c<=e.viewFrom)v&&df(a.doc,c+d)>e.viewFrom?Rc(a):(e.viewFrom+=d,e.viewTo+=d);else if(b<=e.viewFrom&&c>=e.viewTo)Rc(a);else if(b<=e.viewFrom){var f=Tc(a,c,c+d,1);f?(e.view=e.view.slice(f.index),e.viewFrom=f.lineN,e.viewTo+=d):Rc(a)}else if(c>=e.viewTo){var f=Tc(a,b,b,-1);f?(e.view=e.view.slice(0,f.index),e.viewTo=f.lineN):Rc(a)}else{var g=Tc(a,b,b,-1),h=Tc(a,c,c+d,1);g&&h?(e.view=e.view.slice(0,g.in
 dex).concat(Oc(a,g.lineN,h.lineN)).concat(e.view.slice(h.index)),e.viewTo+=d):Rc(a)}var i=e.externalMeasured;i&&(c<i.lineN?i.lineN+=d:b<i.lineN+i.size&&(e.externalMeasured=null))}function Qc(a,b,c){a.curOp.viewChanged=!0;var d=a.display,e=a.display.externalMeasured;if(e&&b>=e.lineN&&b<e.lineN+e.size&&(d.externalMeasured=null),!(b<d.viewFrom||b>=d.viewTo)){var f=d.view[Sc(a,b)];if(null!=f.node){var g=f.changes||(f.changes=[]);-1==Mg(g,c)&&g.push(c)}}}function Rc(a){a.display.viewFrom=a.display.viewTo=a.doc.first,a.display.view=[],a.display.viewOffset=0}function Sc(a,b){if(b>=a.display.viewTo)return null;if(b-=a.display.viewFrom,0>b)return null;for(var c=a.display.view,d=0;d<c.length;d++)if(b-=c[d].size,0>b)return d}function Tc(a,b,c,d){var f,e=Sc(a,b),g=a.display.view;if(!v||c==a.doc.first+a.doc.size)return{index:e,lineN:c};for(var h=0,i=a.display.viewFrom;e>h;h++)i+=g[h].size;if(i!=b){if(d>0){if(e==g.length-1)return null;f=i+g[e].size-b,e++}else f=i-b;b+=f,c+=f}for(;cf(a.doc,c)!=c;)
 {if(e==(0>d?0:g.length-1))return null;c+=d*g[e-(0>d?1:0)].size,e+=d}return{index:e,lineN:c}}function Uc(a,b,c){var d=a.display,e=d.view;0==e.length||b>=d.viewTo||c<=d.viewFrom?(d.view=Oc(a,b,c),d.viewFrom=b):(d.viewFrom>b?d.view=Oc(a,b,d.viewFrom).concat(d.view):d.viewFrom<b&&(d.view=d.view.slice(Sc(a,b))),d.viewFrom=b,d.viewTo<c?d.view=d.view.concat(Oc(a,d.viewTo,c)):d.viewTo>c&&(d.view=d.view.slice(0,Sc(a,c)))),d.viewTo=c}function Vc(a){for(var b=a.display.view,c=0,d=0;d<b.length;d++){var e=b[d];e.hidden||e.node&&!e.changes||++c}return c}function Wc(a){a.display.pollingFast||a.display.poll.set(a.options.pollInterval,function(){Zc(a),a.state.focused&&Wc(a)})}function Xc(a){function c(){var d=Zc(a);d||b?(a.display.pollingFast=!1,Wc(a)):(b=!0,a.display.poll.set(60,c))}var b=!1;a.display.pollingFast=!0,a.display.poll.set(20,c)}function Zc(a){var b=a.display.input,c=a.display.prevInput,f=a.doc;if(!a.state.focused||rh(b)&&!c||bd(a)||a.options.disableInput||a.state.keySeq)return!1;a.stat
 e.pasteIncoming&&a.state.fakedLastChar&&(b.value=b.value.substring(0,b.value.length-1),a.state.fakedLastChar=!1);var g=b.value;if(g==c&&!a.somethingSelected())return!1;if(d&&e>=9&&a.display.inputHasSelection===g||p&&/[\uf700-\uf7ff]/.test(g))return $c(a),!1;var h=!a.curOp;h&&Ac(a),a.display.shift=!1,8203!=g.charCodeAt(0)||f.sel!=a.display.selForContextMenu||c||(c="\u200b");for(var i=0,j=Math.min(c.length,g.length);j>i&&c.charCodeAt(i)==g.charCodeAt(i);)++i;var k=g.slice(i),l=qh(k),m=null;a.state.pasteIncoming&&f.sel.ranges.length>1&&(Yc&&Yc.join("\n")==k?m=0==f.sel.ranges.length%Yc.length&&Ng(Yc,qh):l.length==f.sel.ranges.length&&(m=Ng(l,function(a){return[a]})));for(var n=f.sel.ranges.length-1;n>=0;n--){var o=f.sel.ranges[n],q=o.from(),r=o.to();i<c.length?q=mb(q.line,q.ch-(c.length-i)):a.state.overwrite&&o.empty()&&!a.state.pasteIncoming&&(r=mb(r.line,Math.min(Pf(f,r.line).text.length,r.ch+Kg(l).length)));var s=a.curOp.updateInput,t={from:q,to:r,text:m?m[n%m.length]:l,origin:a.stat
 e.pasteIncoming?"paste":a.state.cutIncoming?"cut":"+input"};if(Rd(a.doc,t),ug(a,"inputRead",a,t),k&&!a.state.pasteIncoming&&a.options.electricChars&&a.options.smartIndent&&o.head.ch<100&&(!n||f.sel.ranges[n-1].head.line!=o.head.line)){var u=a.getModeAt(o.head),v=Ld(t);if(u.electricChars){for(var w=0;w<u.electricChars.length;w++)if(k.indexOf(u.electricChars.charAt(w))>-1){de(a,v.line,"smart");break}}else u.electricInput&&u.electricInput.test(Pf(f,v.line).text.slice(0,v.ch))&&de(a,v.line,"smart")}}return be(a),a.curOp.updateInput=s,a.curOp.typing=!0,g.length>1e3||g.indexOf("\n")>-1?b.value=a.display.prevInput="":a.display.prevInput=g,h&&Cc(a),a.state.pasteIncoming=a.state.cutIncoming=!1,!0}function $c(a,b){var c,f,g=a.doc;if(a.somethingSelected()){a.display.prevInput="";var h=g.sel.primary();c=sh&&(h.to().line-h.from().line>100||(f=a.getSelection()).length>1e3);var i=c?"-":f||a.getSelection();a.display.input.value=i,a.state.focused&&Lg(a.display.input),d&&e>=9&&(a.display.inputHasSele
 ction=i)}else b||(a.display.prevInput=a.display.input.value="",d&&e>=9&&(a.display.inputHasSelection=null));a.display.inaccurateSelection=c}function _c(a){"nocursor"==a.options.readOnly||o&&ah()==a.display.input||a.display.input.focus()}function ad(a){a.state.focused||(_c(a),Hd(a))}function bd(a){return a.options.readOnly||a.doc.cantEdit}function cd(a){function c(){a.state.focused&&setTimeout(Qg(_c,a),0)}function g(b){wg(a,b)||ng(b)}function h(c){if(a.somethingSelected())Yc=a.getSelections(),b.inaccurateSelection&&(b.prevInput="",b.inaccurateSelection=!1,b.input.value=Yc.join("\n"),Lg(b.input));else{for(var d=[],e=[],f=0;f<a.doc.sel.ranges.length;f++){var g=a.doc.sel.ranges[f].head.line,h={anchor:mb(g,0),head:mb(g+1,0)};e.push(h),d.push(a.getRange(h.anchor,h.head))}"cut"==c.type?a.setSelections(e,null,Cg):(b.prevInput="",b.input.value=d.join("\n"),Lg(b.input)),Yc=d}"cut"==c.type&&(a.state.cutIncoming=!0)}var b=a.display;qg(b.scroller,"mousedown",Kc(a,gd)),d&&11>e?qg(b.scroller,"dblc
 lick",Kc(a,function(b){if(!wg(a,b)){var c=fd(a,b);if(c&&!nd(a,b)&&!ed(a.display,b)){kg(b);var d=a.findWordAt(c);Bb(a.doc,d.anchor,d.head)}}})):qg(b.scroller,"dblclick",function(b){wg(a,b)||kg(b)}),qg(b.lineSpace,"selectstart",function(a){ed(b,a)||kg(a)}),t||qg(b.scroller,"contextmenu",function(b){Jd(a,b)}),qg(b.scroller,"scroll",function(){b.scroller.clientHeight&&(rd(a,b.scroller.scrollTop),sd(a,b.scroller.scrollLeft,!0),sg(a,"scroll",a))}),qg(b.scrollbarV,"scroll",function(){b.scroller.clientHeight&&rd(a,b.scrollbarV.scrollTop)}),qg(b.scrollbarH,"scroll",function(){b.scroller.clientHeight&&sd(a,b.scrollbarH.scrollLeft)}),qg(b.scroller,"mousewheel",function(b){vd(a,b)}),qg(b.scroller,"DOMMouseScroll",function(b){vd(a,b)}),qg(b.scrollbarH,"mousedown",c),qg(b.scrollbarV,"mousedown",c),qg(b.wrapper,"scroll",function(){b.wrapper.scrollTop=b.wrapper.scrollLeft=0}),qg(b.input,"keyup",function(b){Fd.call(a,b)}),qg(b.input,"input",function(){d&&e>=9&&a.display.inputHasSelection&&(a.display
 .inputHasSelection=null),Xc(a)}),qg(b.input,"keydown",Kc(a,Dd)),qg(b.input,"keypress",Kc(a,Gd)),qg(b.input,"focus",Qg(Hd,a)),qg(b.input,"blur",Qg(Id,a)),a.options.dragDrop&&(qg(b.scroller,"dragstart",function(b){qd(a,b)}),qg(b.scroller,"dragenter",g),qg(b.scroller,"dragover",g),qg(b.scroller,"drop",Kc(a,pd))),qg(b.scroller,"paste",function(c){ed(b,c)||(a.state.pasteIncoming=!0,_c(a),Xc(a))}),qg(b.input,"paste",function(){if(f&&!a.state.fakedLastChar&&!(new Date-a.state.lastMiddleDown<200)){var c=b.input.selectionStart,d=b.input.selectionEnd;b.input.value+="$",b.input.selectionEnd=d,b.input.selectionStart=c,a.state.fakedLastChar=!0}a.state.pasteIncoming=!0,Xc(a)}),qg(b.input,"cut",h),qg(b.input,"copy",h),k&&qg(b.sizer,"mouseup",function(){ah()==b.input&&b.input.blur(),_c(a)})}function dd(a){var b=a.display;(b.lastWrapHeight!=b.wrapper.clientHeight||b.lastWrapWidth!=b.wrapper.clientWidth)&&(b.cachedCharWidth=b.cachedTextHeight=b.cachedPaddingH=null,a.setSize())}function ed(a,b){for(va
 r c=og(b);c!=a.wrapper;c=c.parentNode)if(!c||c.ignoreEvents||c.parentNode==a.sizer&&c!=a.mover)return!0}function fd(a,b,c,d){var e=a.display;if(!c){var f=og(b);if(f==e.scrollbarH||f==e.scrollbarV||f==e.scrollbarFiller||f==e.gutterFiller)return null}var g,h,i=e.lineSpace.getBoundingClientRect();try{g=b.clientX-i.left,h=b.clientY-i.top}catch(b){return null}var k,j=tc(a,g,h);if(d&&1==j.xRel&&(k=Pf(a.doc,j.line).text).length==j.ch){var l=Gg(k,k.length,a.options.tabSize)-k.length;j=mb(j.line,Math.max(0,Math.round((g-Zb(a.display).left)/xc(a.display))-l))}return j}function gd(a){if(!wg(this,a)){var b=this,c=b.display;if(c.shift=a.shiftKey,ed(c,a))return f||(c.scroller.draggable=!1,setTimeout(function(){c.scroller.draggable=!0},100)),void 0;if(!nd(b,a)){var d=fd(b,a);switch(window.focus(),pg(a)){case 1:d?jd(b,a,d):og(a)==c.scroller&&kg(a);break;case 2:f&&(b.state.lastMiddleDown=+new Date),d&&Bb(b.doc,d),setTimeout(Qg(_c,b),20),kg(a);break;case 3:t&&Jd(b,a)}}}}function jd(a,b,c){setTimeout(
 Qg(ad,a),0);var e,d=+new Date;id&&id.time>d-400&&0==nb(id.pos,c)?e="triple":hd&&hd.time>d-400&&0==nb(hd.pos,c)?(e="double",id={time:d,pos:c}):(e="single",hd={time:d,pos:c});var f=a.doc.sel,g=p?b.metaKey:b.ctrlKey;a.options.dragDrop&&jh&&!bd(a)&&"single"==e&&f.contains(c)>-1&&f.somethingSelected()?kd(a,b,c,g):ld(a,b,c,e,g)}function kd(a,b,c,g){var h=a.display,i=Kc(a,function(j){f&&(h.scroller.draggable=!1),a.state.draggingText=!1,rg(document,"mouseup",i),rg(h.scroller,"drop",i),Math.abs(b.clientX-j.clientX)+Math.abs(b.clientY-j.clientY)<10&&(kg(j),g||Bb(a.doc,c),_c(a),d&&9==e&&setTimeout(function(){document.body.focus(),_c(a)},20))});f&&(h.scroller.draggable=!0),a.state.draggingText=i,h.scroller.dragDrop&&h.scroller.dragDrop(),qg(document,"mouseup",i),qg(h.scroller,"drop",i)}function ld(a,b,c,d,e){function n(b){if(0!=nb(m,b))if(m=b,"rect"==d){for(var e=[],f=a.options.tabSize,k=Gg(Pf(g,c.line).text,c.ch,f),l=Gg(Pf(g,b.line).text,b.ch,f),n=Math.min(k,l),o=Math.max(k,l),p=Math.min(c.lin
 e,b.line),q=Math.min(a.lastLine(),Math.max(c.line,b.line));q>=p;p++){var r=Pf(g,p).text,s=Hg(r,n,f);n==o?e.push(new sb(mb(p,s),mb(p,s))):r.length>s&&e.push(new sb(mb(p,s),mb(p,Hg(r,o,f))))}e.length||e.push(new sb(c,c)),Hb(g,tb(j.ranges.slice(0,i).concat(e),i),{origin:"*mouse",scroll:!1}),a.scrollIntoView(b)}else{var t=h,u=t.anchor,v=b;if("single"!=d){if("double"==d)var w=a.findWordAt(b);else var w=new sb(mb(b.line,0),wb(g,mb(b.line+1,0)));nb(w.anchor,u)>0?(v=w.head,u=qb(t.from(),w.anchor)):(v=w.anchor,u=pb(t.to(),w.head))}var e=j.ranges.slice(0);e[i]=new sb(wb(g,u),v),Hb(g,tb(e,i),Dg)}}function q(b){var c=++p,e=fd(a,b,!0,"rect"==d);if(e)if(0!=nb(e,m)){ad(a),n(e);var h=N(f,g);(e.line>=h.to||e.line<h.from)&&setTimeout(Kc(a,function(){p==c&&q(b)}),150)}else{var i=b.clientY<o.top?-20:b.clientY>o.bottom?20:0;i&&setTimeout(Kc(a,function(){p==c&&(f.scroller.scrollTop+=i,q(b))}),50)}}function r(b){p=1/0,kg(b),_c(a),rg(document,"mousemove",s),rg(document,"mouseup",t),g.history.lastSelOrigin=
 null}var f=a.display,g=a.doc;kg(b);var h,i,j=g.sel;if(e&&!b.shiftKey?(i=g.sel.contains(c),h=i>-1?g.sel.ranges[i]:new sb(c,c)):h=g.sel.primary(),b.altKey)d="rect",e||(h=new sb(c,c)),c=fd(a,b,!0,!0),i=-1;else if("double"==d){var k=a.findWordAt(c);h=a.display.shift||g.extend?Ab(g,h,k.anchor,k.head):k}else if("triple"==d){var l=new sb(mb(c.line,0),wb(g,mb(c.line+1,0)));h=a.display.shift||g.extend?Ab(g,h,l.anchor,l.head):l}else h=Ab(g,h,c);e?i>-1?Db(g,i,h,Dg):(i=g.sel.ranges.length,Hb(g,tb(g.sel.ranges.concat([h]),i),{scroll:!1,origin:"*mouse"})):(i=0,Hb(g,new rb([h],0),Dg),j=g.sel);var m=c,o=f.wrapper.getBoundingClientRect(),p=0,s=Kc(a,function(a){pg(a)?q(a):r(a)}),t=Kc(a,r);qg(document,"mousemove",s),qg(document,"mouseup",t)}function md(a,b,c,d,e){try{var f=b.clientX,g=b.clientY}catch(b){return!1}if(f>=Math.floor(a.display.gutters.getBoundingClientRect().right))return!1;d&&kg(b);var h=a.display,i=h.lineDiv.getBoundingClientRect();if(g>i.bottom||!yg(a,c))return mg(b);g-=i.top-h.viewOffs
 et;for(var j=0;j<a.options.gutters.length;++j){var k=h.gutters.childNodes[j];if(k&&k.getBoundingClientRect().right>=f){var l=Uf(a.doc,g),m=a.options.gutters[j];return e(a,c,a,l,m,b),mg(b)}}}function nd(a,b){return md(a,b,"gutterClick",!0,ug)}function pd(a){var b=this;if(!wg(b,a)&&!ed(b.display,a)){kg(a),d&&(od=+new Date);var c=fd(b,a,!0),e=a.dataTransfer.files;if(c&&!bd(b))if(e&&e.length&&window.FileReader&&window.File)for(var f=e.length,g=Array(f),h=0,i=function(a,d){var e=new FileReader;e.onload=Kc(b,function(){if(g[d]=e.result,++h==f){c=wb(b.doc,c);var a={from:c,to:c,text:qh(g.join("\n")),origin:"paste"};Rd(b.doc,a),Gb(b.doc,ub(c,Ld(a)))}}),e.readAsText(a)},j=0;f>j;++j)i(e[j],j);else{if(b.state.draggingText&&b.doc.sel.contains(c)>-1)return b.state.draggingText(a),setTimeout(Qg(_c,b),20),void 0;try{var g=a.dataTransfer.getData("Text");if(g){if(b.state.draggingText&&!(p?a.metaKey:a.ctrlKey))var k=b.listSelections();if(Ib(b.doc,ub(c,c)),k)for(var j=0;j<k.length;++j)Xd(b.doc,"",k[j].
 anchor,k[j].head,"drag");b.replaceSelection(g,"around","paste"),_c(b)}}catch(a){}}}}function qd(a,b){if(d&&(!a.state.draggingText||+new Date-od<100))return ng(b),void 0;if(!wg(a,b)&&!ed(a.display,b)&&(b.dataTransfer.setData("Text",a.getSelection()),b.dataTransfer.setDragImage&&!j)){var c=Xg("img",null,null,"position: fixed; left: 0; top: 0;");c.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",i&&(c.width=c.height=1,a.display.wrapper.appendChild(c),c._top=c.offsetTop),b.dataTransfer.setDragImage(c,0,0),i&&c.parentNode.removeChild(c)}}function rd(b,c){Math.abs(b.doc.scrollTop-c)<2||(b.doc.scrollTop=c,a||V(b,{top:c}),b.display.scroller.scrollTop!=c&&(b.display.scroller.scrollTop=c),b.display.scrollbarV.scrollTop!=c&&(b.display.scrollbarV.scrollTop=c),a&&V(b),Tb(b,100))}function sd(a,b,c){(c?b==a.doc.scrollLeft:Math.abs(a.doc.scrollLeft-b)<2)||(b=Math.min(b,a.display.scroller.scrollWidth-a.display.scroller.clientWidth),a.doc.scrollLeft=b,O(a),a.display.sc
 roller.scrollLeft!=b&&(a.display.scroller.scrollLeft=b),a.display.scrollbarH.scrollLeft!=b&&(a.display.scrollbarH.scrollLeft=b))}function vd(b,c){var d=c.wheelDeltaX,e=c.wheelDeltaY;null==d&&c.detail&&c.axis==c.HORIZONTAL_AXIS&&(d=c.detail),null==e&&c.detail&&c.axis==c.VERTICAL_AXIS?e=c.detail:null==e&&(e=c.wheelDelta);var g=b.display,h=g.scroller;if(d&&h.scrollWidth>h.clientWidth||e&&h.scrollHeight>h.clientHeight){if(e&&p&&f)a:for(var j=c.target,k=g.view;j!=h;j=j.parentNode)for(var l=0;l<k.length;l++)if(k[l].node==j){b.display.currentWheelTarget=j;break a}if(d&&!a&&!i&&null!=ud)return e&&rd(b,Math.max(0,Math.min(h.scrollTop+e*ud,h.scrollHeight-h.clientHeight))),sd(b,Math.max(0,Math.min(h.scrollLeft+d*ud,h.scrollWidth-h.clientWidth))),kg(c),g.wheelStartX=null,void 0;if(e&&null!=ud){var m=e*ud,n=b.doc.scrollTop,o=n+g.wrapper.clientHeight;0>m?n=Math.max(0,n+m-50):o=Math.min(b.doc.height,o+m+50),V(b,{top:n,bottom:o})}20>td&&(null==g.wheelStartX?(g.wheelStartX=h.scrollLeft,g.wheelStartY
 =h.scrollTop,g.wheelDX=d,g.wheelDY=e,setTimeout(function(){if(null!=g.wheelStartX){var a=h.scrollLeft-g.wheelStartX,b=h.scrollTop-g.wheelStartY,c=b&&g.wheelDY&&b/g.wheelDY||a&&g.wheelDX&&a/g.wheelDX;g.wheelStartX=g.wheelStartY=null,c&&(ud=(ud*td+c)/(td+1),++td)}},200)):(g.wheelDX+=d,g.wheelDY+=e))}}function wd(a,b,c){if("string"==typeof b&&(b=te[b],!b))return!1;a.display.pollingFast&&Zc(a)&&(a.display.pollingFast=!1);var d=a.display.shift,e=!1;try{bd(a)&&(a.state.suppressEdits=!0),c&&(a.display.shift=!1),e=b(a)!=Bg}finally{a.display.shift=d,a.state.suppressEdits=!1}return e}function xd(a,b,c){for(var d=0;d<a.state.keyMaps.length;d++){var e=we(b,a.state.keyMaps[d],c);if(e)return e}return a.options.extraKeys&&we(b,a.options.extraKeys,c)||we(b,a.options.keyMap,c)}function zd(a,b,c,d){var e=a.state.keySeq;if(e){if(xe(b))return"handled";yd.set(50,function(){a.state.keySeq==e&&(a.state.keySeq=null,$c(a))}),b=e+" "+b}var f=xd(a,b,d);return"multi"==f&&(a.state.keySeq=b),"handled"==f&&ug(a,"
 keyHandled",a,b,c),("handled"==f||"multi"==f)&&(kg(c),Sb(a)),e&&!f&&/\'$/.test(b)?(kg(c),!0):!!f}function Ad(a,b){var c=ye(b,!0);return c?b.shiftKey&&!a.state.keySeq?zd(a,"Shift-"+c,b,function(b){return wd(a,b,!0)})||zd(a,c,b,function(b){return("string"==typeof b?/^go[A-Z]/.test(b):b.motion)?wd(a,b):void 0}):zd(a,c,b,function(b){return wd(a,b)}):!1}function Bd(a,b,c){return zd(a,"'"+c+"'",b,function(b){return wd(a,b,!0)})}function Dd(a){var b=this;if(ad(b),!wg(b,a)){d&&11>e&&27==a.keyCode&&(a.returnValue=!1);var c=a.keyCode;b.display.shift=16==c||a.shiftKey;var f=Ad(b,a);i&&(Cd=f?c:null,!f&&88==c&&!sh&&(p?a.metaKey:a.ctrlKey)&&b.replaceSelection("",null,"cut")),18!=c||/\bCodeMirror-crosshair\b/.test(b.display.lineDiv.className)||Ed(b)}}function Ed(a){function c(a){18!=a.keyCode&&a.altKey||(ch(b,"CodeMirror-crosshair"),rg(document,"keyup",c),rg(document,"mouseover",c))}var b=a.display.lineDiv;dh(b,"CodeMirror-crosshair"),qg(document,"keyup",c),qg(document,"mouseover",c)}function Fd(a
 ){16==a.keyCode&&(this.doc.sel.shift=!1),wg(this,a)}function Gd(a){var b=this;if(!(wg(b,a)||a.ctrlKey&&!a.altKey||p&&a.metaKey)){var c=a.keyCode,f=a.charCode;if(i&&c==Cd)return Cd=null,kg(a),void 0;if(!(i&&(!a.which||a.which<10)||k)||!Ad(b,a)){var g=String.fromCharCode(null==f?c:f);Bd(b,a,g)||(d&&e>=9&&(b.display.inputHasSelection=null),Xc(b))}}}function Hd(a){"nocursor"!=a.options.readOnly&&(a.state.focused||(sg(a,"focus",a),a.state.focused=!0,dh(a.display.wrapper,"CodeMirror-focused"),a.curOp||a.display.selForContextMenu==a.doc.sel||($c(a),f&&setTimeout(Qg($c,a,!0),0))),Wc(a),Sb(a))}function Id(a){a.state.focused&&(sg(a,"blur",a),a.state.focused=!1,ch(a.display.wrapper,"CodeMirror-focused")),clearInterval(a.display.blinker),setTimeout(function(){a.state.focused||(a.display.shift=!1)},150)}function Jd(a,b){function m(){if(null!=c.input.selectionStart){var b=a.somethingSelected(),d=c.input.value="\u200b"+(b?c.input.value:"");c.prevInput=b?"":"\u200b",c.input.selectionStart=1,c.input
 .selectionEnd=d.length,c.selForContextMenu=a.doc.sel}}function n(){if(c.inputDiv.style.position="relative",c.input.style.cssText=k,d&&9>e&&(c.scrollbarV.scrollTop=c.scroller.scrollTop=h),Wc(a),null!=c.input.selectionStart){(!d||d&&9>e)&&m();var b=0,f=function(){c.selForContextMenu==a.doc.sel&&0==c.input.selectionStart?Kc(a,te.selectAll)(a):b++<10?c.detectingSelectAll=setTimeout(f,500):$c(a)};c.detectingSelectAll=setTimeout(f,200)}}if(!wg(a,b,"contextmenu")){var c=a.display;if(!ed(c,b)&&!Kd(a,b)){var g=fd(a,b),h=c.scroller.scrollTop;if(g&&!i){var j=a.options.resetSelectionOnContextMenu;j&&-1==a.doc.sel.contains(g)&&Kc(a,Hb)(a.doc,ub(g),Cg);var k=c.input.style.cssText;if(c.inputDiv.style.position="absolute",c.input.style.cssText="position: fixed; width: 30px; height: 30px; top: "+(b.clientY-5)+"px; left: "+(b.clientX-5)+"px; z-index: 1000; background: "+(d?"rgba(255, 255, 255, .05)":"transparent")+"; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter
 : alpha(opacity=5);",f)var l=window.scrollY;if(_c(a),f&&window.scrollTo(null,l),$c(a),a.somethingSelected()||(c.input.value=c.prevInput=" "),c.selForContextMenu=a.doc.sel,clearTimeout(c.detectingSelectAll),d&&e>=9&&m(),t){ng(b);var o=function(){rg(window,"mouseup",o),setTimeout(n,20)};qg(window,"mouseup",o)}else setTimeout(n,50)}}}}function Kd(a,b){return yg(a,"gutterContextMenu")?md(a,b,"gutterContextMenu",!1,sg):!1}function Md(a,b){if(nb(a,b.from)<0)return a;if(nb(a,b.to)<=0)return Ld(b);var c=a.line+b.text.length-(b.to.line-b.from.line)-1,d=a.ch;return a.line==b.to.line&&(d+=Ld(b).ch-b.to.ch),mb(c,d)}function Nd(a,b){for(var c=[],d=0;d<a.sel.ranges.length;d++){var e=a.sel.ranges[d];c.push(new sb(Md(e.anchor,b),Md(e.head,b)))}return tb(c,a.sel.primIndex)}function Od(a,b,c){return a.line==b.line?mb(c.line,a.ch-b.ch+c.ch):mb(c.line+(a.line-b.line),a.ch)}function Pd(a,b,c){for(var d=[],e=mb(a.first,0),f=e,g=0;g<b.length;g++){var h=b[g],i=Od(h.from,e,f),j=Od(Ld(h),e,f);if(e=h.to,f=j,"
 around"==c){var k=a.sel.ranges[g],l=nb(k.head,k.anchor)<0;d[g]=new sb(l?j:i,l?i:j)}else d[g]=new sb(i,i)}return new rb(d,a.sel.primIndex)}function Qd(a,b,c){var d={canceled:!1,from:b.from,to:b.to,text:b.text,origin:b.origin,cancel:function(){this.canceled=!0}};return c&&(d.update=function(b,c,d,e){b&&(this.from=wb(a,b)),c&&(this.to=wb(a,c)),d&&(this.text=d),void 0!==e&&(this.origin=e)}),sg(a,"beforeChange",a,d),a.cm&&sg(a.cm,"beforeChange",a.cm,d),d.canceled?null:{from:d.from,to:d.to,text:d.text,origin:d.origin}}function Rd(a,b,c){if(a.cm){if(!a.cm.curOp)return Kc(a.cm,Rd)(a,b,c);if(a.cm.state.suppressEdits)return}if(!(yg(a,"beforeChange")||a.cm&&yg(a.cm,"beforeChange"))||(b=Qd(a,b,!0))){var d=u&&!c&&Se(a,b.from,b.to);if(d)for(var e=d.length-1;e>=0;--e)Sd(a,{from:d[e].from,to:d[e].to,text:e?[""]:b.text});else Sd(a,b)}}function Sd(a,b){if(1!=b.text.length||""!=b.text[0]||0!=nb(b.from,b.to)){var c=Nd(a,b);_f(a,b,c,a.cm?a.cm.curOp.id:0/0),Vd(a,b,c,Pe(a,b));var d=[];Nf(a,function(a,c){c
 ||-1!=Mg(d,a.history)||(jg(a.history,b),d.push(a.history)),Vd(a,b,null,Pe(a,b))})}}function Td(a,b,c){if(!a.cm||!a.cm.state.suppressEdits){for(var e,d=a.history,f=a.sel,g="undo"==b?d.done:d.undone,h="undo"==b?d.undone:d.done,i=0;i<g.length&&(e=g[i],c?!e.ranges||e.equals(a.sel):e.ranges);i++);if(i!=g.length){for(d.lastOrigin=d.lastSelOrigin=null;e=g.pop(),e.ranges;){if(cg(e,h),c&&!e.equals(a.sel))return Hb(a,e,{clearRedo:!1}),void 0;f=e}var j=[];cg(f,h),h.push({changes:j,generation:d.generation}),d.generation=e.generation||++d.maxGeneration;for(var k=yg(a,"beforeChange")||a.cm&&yg(a.cm,"beforeChange"),i=e.changes.length-1;i>=0;--i){var l=e.changes[i];if(l.origin=b,k&&!Qd(a,l,!1))return g.length=0,void 0;j.push(Yf(a,l));var m=i?Nd(a,l):Kg(g);Vd(a,l,m,Re(a,l)),!i&&a.cm&&a.cm.scrollIntoView({from:l.from,to:Ld(l)});var n=[];Nf(a,function(a,b){b||-1!=Mg(n,a.history)||(jg(a.history,l),n.push(a.history)),Vd(a,l,null,Re(a,l))})}}}}function Ud(a,b){if(0!=b&&(a.first+=b,a.sel=new rb(Ng(a.sel.r
 anges,function(a){return new sb(mb(a.anchor.line+b,a.anchor.ch),mb(a.head.line+b,a.head.ch))}),a.sel.primIndex),a.cm)){Pc(a.cm,a.first,a.first-b,b);for(var c=a.cm.display,d=c.viewFrom;d<c.viewTo;d++)Qc(a.cm,d,"gutter")}}function Vd(a,b,c,d){if(a.cm&&!a.cm.curOp)return Kc(a.cm,Vd)(a,b,c,d);if(b.to.line<a.first)return Ud(a,b.text.length-1-(b.to.line-b.from.line)),void 0;if(!(b.from.line>a.lastLine())){if(b.from.line<a.first){var e=b.text.length-1-(a.first-b.from.line);Ud(a,e),b={from:mb(a.first,0),to:mb(b.to.line+e,b.to.ch),text:[Kg(b.text)],origin:b.origin}}var f=a.lastLine();b.to.line>f&&(b={from:b.from,to:mb(f,Pf(a,f).text.length),text:[b.text[0]],origin:b.origin}),b.removed=Qf(a,b.from,b.to),c||(c=Nd(a,b)),a.cm?Wd(a.cm,b,d):Gf(a,b,d),Ib(a,c,Cg)}}function Wd(a,b,c){var d=a.doc,e=a.display,f=b.from,g=b.to,h=!1,i=f.line;a.options.lineWrapping||(i=Tf(af(Pf(d,f.line))),d.iter(i,g.line+1,function(a){return a==e.maxLine?(h=!0,!0):void 0})),d.sel.contains(b.from,b.to)>-1&&xg(a),Gf(d,b,c,B
 (a)),a.options.lineWrapping||(d.iter(i,f.line+b.text.length,function(a){var b=H(a);b>e.maxLineLength&&(e.maxLine=a,e.maxLineLength=b,e.maxLineChanged=!0,h=!1)}),h&&(a.curOp.updateMaxLine=!0)),d.frontier=Math.min(d.frontier,f.line),Tb(a,400);var j=b.text.length-(g.line-f.line)-1;f.line!=g.line||1!=b.text.length||Ff(a.doc,b)?Pc(a,f.line,g.line+1,j):Qc(a,f.line,"text");var k=yg(a,"changes"),l=yg(a,"change");if(l||k){var m={from:f,to:g,text:b.text,removed:b.removed,origin:b.origin};l&&ug(a,"change",a,m),k&&(a.curOp.changeObjs||(a.curOp.changeObjs=[])).push(m)}a.display.selForContextMenu=null}function Xd(a,b,c,d,e){if(d||(d=c),nb(d,c)<0){var f=d;d=c,c=f}"string"==typeof b&&(b=qh(b)),Rd(a,{from:c,to:d,text:b,origin:e})}function Yd(a,b){var c=a.display,d=c.sizer.getBoundingClientRect(),e=null;if(b.top+d.top<0?e=!0:b.bottom+d.top>(window.innerHeight||document.documentElement.clientHeight)&&(e=!1),null!=e&&!m){var f=Xg("div","\u200b",null,"position: absolute; top: "+(b.top-c.viewOffset-Xb(a.
 display))+"px; height: "+(b.bottom-b.top+Ag)+"px; left: "+b.left+"px; width: 2px;");a.display.lineSpace.appendChild(f),f.scrollIntoView(e),a.display.lineSpace.removeChild(f)}}function Zd(a,b,c,d){null==d&&(d=0);for(var e=0;5>e;e++){var f=!1,g=qc(a,b),h=c&&c!=b?qc(a,c):g,i=_d(a,Math.min(g.left,h.left),Math.min(g.top,h.top)-d,Math.max(g.left,h.left),Math.max(g.bottom,h.bottom)+d),j=a.doc.scrollTop,k=a.doc.scrollLeft;if(null!=i.scrollTop&&(rd(a,i.scrollTop),Math.abs(a.doc.scrollTop-j)>1&&(f=!0)),null!=i.scrollLeft&&(sd(a,i.scrollLeft),Math.abs(a.doc.scrollLeft-k)>1&&(f=!0)),!f)return g}}function $d(a,b,c,d,e){var f=_d(a,b,c,d,e);null!=f.scrollTop&&rd(a,f.scrollTop),null!=f.scrollLeft&&sd(a,f.scrollLeft)}function _d(a,b,c,d,e){var f=a.display,g=wc(a.display);0>c&&(c=0);var h=a.curOp&&null!=a.curOp.scrollTop?a.curOp.scrollTop:f.scroller.scrollTop,i=f.scroller.clientHeight-Ag,j={};e-c>i&&(e=c+i);var k=a.doc.height+Yb(f),l=g>c,m=e>k-g;if(h>c)j.scrollTop=l?0:c;else if(e>h+i){var n=Math.min(
 c,(m?k:e)-i);n!=h&&(j.scrollTop=n)}var o=a.curOp&&null!=a.curOp.scrollLeft?a.curOp.scrollLeft:f.scroller.scrollLeft,p=f.scroller.clientWidth-Ag-f.gutters.offsetWidth,q=d-b>p;return q&&(d=b+p),10>b?j.scrollLeft=0:o>b?j.scrollLeft=Math.max(0,b-(q?0:10)):d>p+o-3&&(j.scrollLeft=d+(q?0:10)-p),j}function ae(a,b,c){(null!=b||null!=c)&&ce(a),null!=b&&(a.curOp.scrollLeft=(null==a.curOp.scrollLeft?a.doc.scrollLeft:a.curOp.scrollLeft)+b),null!=c&&(a.curOp.scrollTop=(null==a.curOp.scrollTop?a.doc.scrollTop:a.curOp.scrollTop)+c)}function be(a){ce(a);var b=a.getCursor(),c=b,d=b;a.options.lineWrapping||(c=b.ch?mb(b.line,b.ch-1):b,d=mb(b.line,b.ch+1)),a.curOp.scrollToPos={from:c,to:d,margin:a.options.cursorScrollMargin,isCursor:!0}}function ce(a){var b=a.curOp.scrollToPos;if(b){a.curOp.scrollToPos=null;var c=rc(a,b.from),d=rc(a,b.to),e=_d(a,Math.min(c.left,d.left),Math.min(c.top,d.top)-b.margin,Math.max(c.right,d.right),Math.max(c.bottom,d.bottom)+b.margin);a.scrollTo(e.scrollLeft,e.scrollTop)}}fun
 ction de(a,b,c,d){var f,e=a.doc;null==c&&(c="add"),"smart"==c&&(e.mode.indent?f=Wb(a,b):c="prev");var g=a.options.tabSize,h=Pf(e,b),i=Gg(h.text,null,g);h.stateAfter&&(h.stateAfter=null);var k,j=h.text.match(/^\s*/)[0];if(d||/\S/.test(h.text)){if("smart"==c&&(k=e.mode.indent(f,h.text.slice(j.length),h.text),k==Bg||k>150)){if(!d)return;c="prev"}}else k=0,c="not";"prev"==c?k=b>e.first?Gg(Pf(e,b-1).text,null,g):0:"add"==c?k=i+a.options.indentUnit:"subtract"==c?k=i-a.options.indentUnit:"number"==typeof c&&(k=i+c),k=Math.max(0,k);var l="",m=0;if(a.options.indentWithTabs)for(var n=Math.floor(k/g);n;--n)m+=g,l+="	";if(k>m&&(l+=Jg(k-m)),l!=j)Xd(e,l,mb(b,0),mb(b,j.length),"+input");else for(var n=0;n<e.sel.ranges.length;n++){var o=e.sel.ranges[n];if(o.head.line==b&&o.head.ch<j.length){var m=mb(b,j.length);Db(e,n,new sb(m,m));break}}h.stateAfter=null}function ee(a,b,c,d){var e=b,f=b;return"number"==typeof b?f=Pf(a,vb(a,b)):e=Tf(b),null==e?null:(d(f,e)&&a.cm&&Qc(a.cm,e,c),f)}function fe(a,b){fo
 r(var c=a.doc.sel.ranges,d=[],e=0;e<c.length;e++){for(var f=b(c[e]);d.length&&nb(f.from,Kg(d).to)<=0;){var g=d.pop();if(nb(g.from,f.from)<0){f.from=g.from;break}}d.push(f)}Jc(a,function(){for(var b=d.length-1;b>=0;b--)Xd(a.doc,"",d[b].from,d[b].to,"+delete");be(a)})}function ge(a,b,c,d,e){function k(){var b=f+c;return b<a.first||b>=a.first+a.size?j=!1:(f=b,i=Pf(a,b))}function l(a){var b=(e?Ih:Jh)(i,g,c,!0);if(null==b){if(a||!k())return j=!1;g=e?(0>c?Ah:zh)(i):0>c?i.text.length:0}else g=b;return!0}var f=b.line,g=b.ch,h=c,i=Pf(a,f),j=!0;if("char"==d)l();else if("column"==d)l(!0);else if("word"==d||"group"==d)for(var m=null,n="group"==d,o=a.cm&&a.cm.getHelper(b,"wordChars"),p=!0;!(0>c)||l(!p);p=!1){var q=i.text.charAt(g)||"\n",r=Tg(q,o)?"w":n&&"\n"==q?"n":!n||/\s/.test(q)?null:"p";if(!n||p||r||(r="s"),m&&m!=r){0>c&&(c=1,l());break}if(r&&(m=r),c>0&&!l(!p))break}var s=Mb(a,mb(f,g),h,!0);return j||(s.hitSide=!0),s}function he(a,b,c,d){var g,e=a.doc,f=b.left;if("page"==d){var h=Math.min(a.
 display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight);g=b.top+c*(h-(0>c?1.5:.5)*wc(a.display))}else"line"==d&&(g=c>0?b.bottom+3:b.top-3);for(;;){var i=tc(a,f,g);if(!i.outside)break;if(0>c?0>=g:g>=e.height){i.hitSide=!0;break}g+=5*c}return i}function ke(a,b,c,d){w.defaults[a]=b,c&&(je[a]=d?function(a,b,d){d!=le&&c(a,b,d)}:c)}function ve(a){for(var c,d,e,f,b=a.split(/-(?!$)/),a=b[b.length-1],g=0;g<b.length-1;g++){var h=b[g];if(/^(cmd|meta|m)$/i.test(h))f=!0;else if(/^a(lt)?$/i.test(h))c=!0;else if(/^(c|ctrl|control)$/i.test(h))d=!0;else{if(!/^s(hift)$/i.test(h))throw new Error("Unrecognized modifier name: "+h);e=!0}}return c&&(a="Alt-"+a),d&&(a="Ctrl-"+a),f&&(a="Cmd-"+a),e&&(a="Shift-"+a),a}function ze(a){return"string"==typeof a?ue[a]:a}function De(a,b,c,d,e){if(d&&d.shared)return Fe(a,b,c,d,e);if(a.cm&&!a.cm.curOp)return Kc(a.cm,De)(a,b,c,d,e);var f=new Be(a,e),g=nb(b,c);if(d&&Pg(d,f,!1),g>0||0==g&&f.clearWhenEmpty!==!1)return f;if(f.replacedWith&&(
 f.collapsed=!0,f.widgetNode=Xg("span",[f.replacedWith],"CodeMirror-widget"),d.handleMouseEvents||(f.widgetNode.ignoreEvents=!0),d.insertLeft&&(f.widgetNode.insertLeft=!0)),f.collapsed){if(_e(a,b.line,b,c,f)||b.line!=c.line&&_e(a,c.line,b,c,f))throw new Error("Inserting collapsed marker partially overlapping an existing one");
+v=!0}f.addToHistory&&_f(a,{from:b,to:c,origin:"markText"},a.sel,0/0);var j,h=b.line,i=a.cm;if(a.iter(h,c.line+1,function(a){i&&f.collapsed&&!i.options.lineWrapping&&af(a)==i.display.maxLine&&(j=!0),f.collapsed&&h!=b.line&&Sf(a,0),Me(a,new Je(f,h==b.line?b.ch:null,h==c.line?c.ch:null)),++h}),f.collapsed&&a.iter(b.line,c.line+1,function(b){ef(a,b)&&Sf(b,0)}),f.clearOnEnter&&qg(f,"beforeCursorEnter",function(){f.clear()}),f.readOnly&&(u=!0,(a.history.done.length||a.history.undone.length)&&a.clearHistory()),f.collapsed&&(f.id=++Ce,f.atomic=!0),i){if(j&&(i.curOp.updateMaxLine=!0),f.collapsed)Pc(i,b.line,c.line+1);else if(f.className||f.title||f.startStyle||f.endStyle)for(var k=b.line;k<=c.line;k++)Qc(i,k,"text");f.atomic&&Kb(i.doc),ug(i,"markerAdded",i,f)}return f}function Fe(a,b,c,d,e){d=Pg(d),d.shared=!1;var f=[De(a,b,c,d,e)],g=f[0],h=d.widgetNode;return Nf(a,function(a){h&&(d.widgetNode=h.cloneNode(!0)),f.push(De(a,wb(a,b),wb(a,c),d,e));for(var i=0;i<a.linked.length;++i)if(a.linked[i]
 .isParent)return;g=Kg(f)}),new Ee(f,g)}function Ge(a){return a.findMarks(mb(a.first,0),a.clipPos(mb(a.lastLine())),function(a){return a.parent})}function He(a,b){for(var c=0;c<b.length;c++){var d=b[c],e=d.find(),f=a.clipPos(e.from),g=a.clipPos(e.to);if(nb(f,g)){var h=De(a,f,g,d.primary,d.primary.type);d.markers.push(h),h.parent=d}}}function Ie(a){for(var b=0;b<a.length;b++){var c=a[b],d=[c.primary.doc];Nf(c.primary.doc,function(a){d.push(a)});for(var e=0;e<c.markers.length;e++){var f=c.markers[e];-1==Mg(d,f.doc)&&(f.parent=null,c.markers.splice(e--,1))}}}function Je(a,b,c){this.marker=a,this.from=b,this.to=c}function Ke(a,b){if(a)for(var c=0;c<a.length;++c){var d=a[c];if(d.marker==b)return d}}function Le(a,b){for(var c,d=0;d<a.length;++d)a[d]!=b&&(c||(c=[])).push(a[d]);return c}function Me(a,b){a.markedSpans=a.markedSpans?a.markedSpans.concat([b]):[b],b.marker.attachLine(a)}function Ne(a,b,c){if(a)for(var e,d=0;d<a.length;++d){var f=a[d],g=f.marker,h=null==f.from||(g.inclusiveLeft?f
 .from<=b:f.from<b);if(h||f.from==b&&"bookmark"==g.type&&(!c||!f.marker.insertLeft)){var i=null==f.to||(g.inclusiveRight?f.to>=b:f.to>b);(e||(e=[])).push(new Je(g,f.from,i?null:f.to))}}return e}function Oe(a,b,c){if(a)for(var e,d=0;d<a.length;++d){var f=a[d],g=f.marker,h=null==f.to||(g.inclusiveRight?f.to>=b:f.to>b);if(h||f.from==b&&"bookmark"==g.type&&(!c||f.marker.insertLeft)){var i=null==f.from||(g.inclusiveLeft?f.from<=b:f.from<b);(e||(e=[])).push(new Je(g,i?null:f.from-b,null==f.to?null:f.to-b))}}return e}function Pe(a,b){var c=yb(a,b.from.line)&&Pf(a,b.from.line).markedSpans,d=yb(a,b.to.line)&&Pf(a,b.to.line).markedSpans;if(!c&&!d)return null;var e=b.from.ch,f=b.to.ch,g=0==nb(b.from,b.to),h=Ne(c,e,g),i=Oe(d,f,g),j=1==b.text.length,k=Kg(b.text).length+(j?e:0);if(h)for(var l=0;l<h.length;++l){var m=h[l];if(null==m.to){var n=Ke(i,m.marker);n?j&&(m.to=null==n.to?null:n.to+k):m.to=e}}if(i)for(var l=0;l<i.length;++l){var m=i[l];if(null!=m.to&&(m.to+=k),null==m.from){var n=Ke(h,m.mark
 er);n||(m.from=k,j&&(h||(h=[])).push(m))}else m.from+=k,j&&(h||(h=[])).push(m)}h&&(h=Qe(h)),i&&i!=h&&(i=Qe(i));var o=[h];if(!j){var q,p=b.text.length-2;if(p>0&&h)for(var l=0;l<h.length;++l)null==h[l].to&&(q||(q=[])).push(new Je(h[l].marker,null,null));for(var l=0;p>l;++l)o.push(q);o.push(i)}return o}function Qe(a){for(var b=0;b<a.length;++b){var c=a[b];null!=c.from&&c.from==c.to&&c.marker.clearWhenEmpty!==!1&&a.splice(b--,1)}return a.length?a:null}function Re(a,b){var c=fg(a,b),d=Pe(a,b);if(!c)return d;if(!d)return c;for(var e=0;e<c.length;++e){var f=c[e],g=d[e];if(f&&g)a:for(var h=0;h<g.length;++h){for(var i=g[h],j=0;j<f.length;++j)if(f[j].marker==i.marker)continue a;f.push(i)}else g&&(c[e]=g)}return c}function Se(a,b,c){var d=null;if(a.iter(b.line,c.line+1,function(a){if(a.markedSpans)for(var b=0;b<a.markedSpans.length;++b){var c=a.markedSpans[b].marker;!c.readOnly||d&&-1!=Mg(d,c)||(d||(d=[])).push(c)}}),!d)return null;for(var e=[{from:b,to:c}],f=0;f<d.length;++f)for(var g=d[f],h=
 g.find(0),i=0;i<e.length;++i){var j=e[i];if(!(nb(j.to,h.from)<0||nb(j.from,h.to)>0)){var k=[i,1],l=nb(j.from,h.from),m=nb(j.to,h.to);(0>l||!g.inclusiveLeft&&!l)&&k.push({from:j.from,to:h.from}),(m>0||!g.inclusiveRight&&!m)&&k.push({from:h.to,to:j.to}),e.splice.apply(e,k),i+=k.length-1}}return e}function Te(a){var b=a.markedSpans;if(b){for(var c=0;c<b.length;++c)b[c].marker.detachLine(a);a.markedSpans=null}}function Ue(a,b){if(b){for(var c=0;c<b.length;++c)b[c].marker.attachLine(a);a.markedSpans=b}}function Ve(a){return a.inclusiveLeft?-1:0}function We(a){return a.inclusiveRight?1:0}function Xe(a,b){var c=a.lines.length-b.lines.length;if(0!=c)return c;var d=a.find(),e=b.find(),f=nb(d.from,e.from)||Ve(a)-Ve(b);if(f)return-f;var g=nb(d.to,e.to)||We(a)-We(b);return g?g:b.id-a.id}function Ye(a,b){var d,c=v&&a.markedSpans;if(c)for(var e,f=0;f<c.length;++f)e=c[f],e.marker.collapsed&&null==(b?e.from:e.to)&&(!d||Xe(d,e.marker)<0)&&(d=e.marker);return d}function Ze(a){return Ye(a,!0)}function
  $e(a){return Ye(a,!1)}function _e(a,b,c,d,e){var f=Pf(a,b),g=v&&f.markedSpans;if(g)for(var h=0;h<g.length;++h){var i=g[h];if(i.marker.collapsed){var j=i.marker.find(0),k=nb(j.from,c)||Ve(i.marker)-Ve(e),l=nb(j.to,d)||We(i.marker)-We(e);if(!(k>=0&&0>=l||0>=k&&l>=0)&&(0>=k&&(nb(j.to,c)>0||i.marker.inclusiveRight&&e.inclusiveLeft)||k>=0&&(nb(j.from,d)<0||i.marker.inclusiveLeft&&e.inclusiveRight)))return!0}}}function af(a){for(var b;b=Ze(a);)a=b.find(-1,!0).line;return a}function bf(a){for(var b,c;b=$e(a);)a=b.find(1,!0).line,(c||(c=[])).push(a);return c}function cf(a,b){var c=Pf(a,b),d=af(c);return c==d?b:Tf(d)}function df(a,b){if(b>a.lastLine())return b;var d,c=Pf(a,b);if(!ef(a,c))return b;for(;d=$e(c);)c=d.find(1,!0).line;return Tf(c)+1}function ef(a,b){var c=v&&b.markedSpans;if(c)for(var d,e=0;e<c.length;++e)if(d=c[e],d.marker.collapsed){if(null==d.from)return!0;if(!d.marker.widgetNode&&0==d.from&&d.marker.inclusiveLeft&&ff(a,b,d))return!0}}function ff(a,b,c){if(null==c.to){var d=c
 .marker.find(1,!0);return ff(a,d.line,Ke(d.line.markedSpans,c.marker))}if(c.marker.inclusiveRight&&c.to==b.text.length)return!0;for(var e,f=0;f<b.markedSpans.length;++f)if(e=b.markedSpans[f],e.marker.collapsed&&!e.marker.widgetNode&&e.from==c.to&&(null==e.to||e.to!=c.from)&&(e.marker.inclusiveLeft||c.marker.inclusiveRight)&&ff(a,b,e))return!0}function hf(a,b,c){Vf(b)<(a.curOp&&a.curOp.scrollTop||a.doc.scrollTop)&&ae(a,null,c)}function jf(a){if(null!=a.height)return a.height;if(!_g(document.body,a.node)){var b="position: relative;";a.coverGutter&&(b+="margin-left: -"+a.cm.getGutterElement().offsetWidth+"px;"),$g(a.cm.display.measure,Xg("div",[a.node],null,b))}return a.height=a.node.offsetHeight}function kf(a,b,c,d){var e=new gf(a,c,d);return e.noHScroll&&(a.display.alignWidgets=!0),ee(a.doc,b,"widget",function(b){var c=b.widgets||(b.widgets=[]);if(null==e.insertAt?c.push(e):c.splice(Math.min(c.length-1,Math.max(0,e.insertAt)),0,e),e.line=b,!ef(a.doc,b)){var d=Vf(b)<a.doc.scrollTop;Sf
 (b,b.height+jf(e)),d&&ae(a,null,e.height),a.curOp.forceUpdate=!0}return!0}),e}function mf(a,b,c,d){a.text=b,a.stateAfter&&(a.stateAfter=null),a.styles&&(a.styles=null),null!=a.order&&(a.order=null),Te(a),Ue(a,c);var e=d?d(a):1;e!=a.height&&Sf(a,e)}function nf(a){a.parent=null,Te(a)}function of(a,b){if(a)for(;;){var c=a.match(/(?:^|\s+)line-(background-)?(\S+)/);if(!c)break;a=a.slice(0,c.index)+a.slice(c.index+c[0].length);var d=c[1]?"bgClass":"textClass";null==b[d]?b[d]=c[2]:new RegExp("(?:^|s)"+c[2]+"(?:$|s)").test(b[d])||(b[d]+=" "+c[2])}return a}function pf(a,b){if(a.blankLine)return a.blankLine(b);if(a.innerMode){var c=w.innerMode(a,b);return c.mode.blankLine?c.mode.blankLine(c.state):void 0}}function qf(a,b,c){for(var d=0;10>d;d++){var e=a.token(b,c);if(b.pos>b.start)return e}throw new Error("Mode "+a.name+" failed to advance stream.")}function rf(a,b,c,d,e,f,g){var h=c.flattenSpans;null==h&&(h=a.options.flattenSpans);var l,i=0,j=null,k=new Ae(b,a.options.tabSize);for(""==b&&of
 (pf(c,d),f);!k.eol();){if(k.pos>a.options.maxHighlightLength?(h=!1,g&&uf(a,b,d,k.pos),k.pos=b.length,l=null):l=of(qf(c,k,d),f),a.options.addModeClass){var m=w.innerMode(c,d).mode.name;m&&(l="m-"+(l?m+" "+l:m))}h&&j==l||(i<k.start&&e(k.start,j),i=k.start,j=l),k.start=k.pos}for(;i<k.pos;){var n=Math.min(k.pos,i+5e4);e(n,j),i=n}}function sf(a,b,c,d){var e=[a.state.modeGen],f={};rf(a,b.text,a.doc.mode,c,function(a,b){e.push(a,b)},f,d);for(var g=0;g<a.state.overlays.length;++g){var h=a.state.overlays[g],i=1,j=0;rf(a,b.text,h.mode,!0,function(a,b){for(var c=i;a>j;){var d=e[i];d>a&&e.splice(i,1,a,e[i+1],d),i+=2,j=Math.min(a,d)}if(b)if(h.opaque)e.splice(c,i-c,a,"cm-overlay "+b),i=c+2;else for(;i>c;c+=2){var f=e[c+1];e[c+1]=(f?f+" ":"")+"cm-overlay "+b}},f)}return{styles:e,classes:f.bgClass||f.textClass?f:null}}function tf(a,b,c){if(!b.styles||b.styles[0]!=a.state.modeGen){var d=sf(a,b,b.stateAfter=Wb(a,Tf(b)));b.styles=d.styles,d.classes?b.styleClasses=d.classes:b.styleClasses&&(b.styleClas
 ses=null),c===a.doc.frontier&&a.doc.frontier++}return b.styles}function uf(a,b,c,d){var e=a.doc.mode,f=new Ae(b,a.options.tabSize);for(f.start=f.pos=d||0,""==b&&pf(e,c);!f.eol()&&f.pos<=a.options.maxHighlightLength;)qf(e,f,c),f.start=f.pos}function xf(a,b){if(!a||/^\s*$/.test(a))return null;var c=b.addModeClass?wf:vf;return c[a]||(c[a]=a.replace(/\S+/g,"cm-$&"))}function yf(a,b){var c=Xg("span",null,null,f?"padding-right: .1px":null),e={pre:Xg("pre",[c]),content:c,col:0,pos:0,cm:a};b.measure={};for(var g=0;g<=(b.rest?b.rest.length:0);g++){var i,h=g?b.rest[g-1]:b.line;e.pos=0,e.addToken=Af,(d||f)&&a.getOption("lineWrapping")&&(e.addToken=Bf(e.addToken)),ph(a.display.measure)&&(i=Wf(h))&&(e.addToken=Cf(e.addToken,i)),e.map=[];var j=b!=a.display.externalMeasured&&Tf(h);Ef(h,e,tf(a,h,j)),h.styleClasses&&(h.styleClasses.bgClass&&(e.bgClass=eh(h.styleClasses.bgClass,e.bgClass||"")),h.styleClasses.textClass&&(e.textClass=eh(h.styleClasses.textClass,e.textClass||""))),0==e.map.length&&e.map
 .push(0,0,e.content.appendChild(nh(a.display.measure))),0==g?(b.measure.map=e.map,b.measure.cache={}):((b.measure.maps||(b.measure.maps=[])).push(e.map),(b.measure.caches||(b.measure.caches=[])).push({}))}return sg(a,"renderLine",a,b.line,e.pre),e.pre.className&&(e.textClass=eh(e.pre.className,e.textClass||"")),e}function zf(a){var b=Xg("span","\u2022","cm-invalidchar");return b.title="\\u"+a.charCodeAt(0).toString(16),b}function Af(a,b,c,f,g,h){if(b){var i=a.cm.options.specialChars,j=!1;if(i.test(b))for(var k=document.createDocumentFragment(),l=0;;){i.lastIndex=l;var m=i.exec(b),n=m?m.index-l:b.length-l;if(n){var o=document.createTextNode(b.slice(l,l+n));d&&9>e?k.appendChild(Xg("span",[o])):k.appendChild(o),a.map.push(a.pos,a.pos+n,o),a.col+=n,a.pos+=n}if(!m)break;if(l+=n+1,"	"==m[0]){var p=a.cm.options.tabSize,q=p-a.col%p,o=k.appendChild(Xg("span",Jg(q),"cm-tab"));a.col+=q}else{var o=a.cm.options.specialCharPlaceholder(m[0]);d&&9>e?k.appendChild(Xg("span",[o])):k.appendChild(o),a.
 col+=1}a.map.push(a.pos,a.pos+1,o),a.pos++}else{a.col+=b.length;var k=document.createTextNode(b);a.map.push(a.pos,a.pos+b.length,k),d&&9>e&&(j=!0),a.pos+=b.length}if(c||f||g||j){var r=c||"";f&&(r+=f),g&&(r+=g);var s=Xg("span",[k],r);return h&&(s.title=h),a.content.appendChild(s)}a.content.appendChild(k)}}function Bf(a){function b(a){for(var b=" ",c=0;c<a.length-2;++c)b+=c%2?" ":"\xa0";return b+=" "}return function(c,d,e,f,g,h){a(c,d.replace(/ {3,}/g,b),e,f,g,h)}}function Cf(a,b){return function(c,d,e,f,g,h){e=e?e+" cm-force-border":"cm-force-border";for(var i=c.pos,j=i+d.length;;){for(var k=0;k<b.length;k++){var l=b[k];if(l.to>i&&l.from<=i)break}if(l.to>=j)return a(c,d,e,f,g,h);a(c,d.slice(0,l.to-i),e,f,null,h),f=null,d=d.slice(l.to-i),i=l.to}}}function Df(a,b,c,d){var e=!d&&c.widgetNode;e&&(a.map.push(a.pos,a.pos+b,e),a.content.appendChild(e)),a.pos+=b}function Ef(a,b,c){var d=a.markedSpans,e=a.text,f=0;if(d)for(var k,m,n,o,p,q,h=e.length,i=0,g=1,j="",l=0;;){if(l==i){m=n=o=p="",q=n
 ull,l=1/0;for(var r=[],s=0;s<d.length;++s){var t=d[s],u=t.marker;t.from<=i&&(null==t.to||t.to>i)?(null!=t.to&&l>t.to&&(l=t.to,n=""),u.className&&(m+=" "+u.className),u.startStyle&&t.from==i&&(o+=" "+u.startStyle),u.endStyle&&t.to==l&&(n+=" "+u.endStyle),u.title&&!p&&(p=u.title),u.collapsed&&(!q||Xe(q.marker,u)<0)&&(q=t)):t.from>i&&l>t.from&&(l=t.from),"bookmark"==u.type&&t.from==i&&u.widgetNode&&r.push(u)}if(q&&(q.from||0)==i&&(Df(b,(null==q.to?h+1:q.to)-i,q.marker,null==q.from),null==q.to))return;if(!q&&r.length)for(var s=0;s<r.length;++s)Df(b,0,r[s])}if(i>=h)break;for(var v=Math.min(h,l);;){if(j){var w=i+j.length;if(!q){var x=w>v?j.slice(0,v-i):j;b.addToken(b,x,k?k+m:m,o,i+x.length==l?n:"",p)}if(w>=v){j=j.slice(v-i),i=v;break}i=w,o=""}j=e.slice(f,f=c[g++]),k=xf(c[g++],b.cm.options)}}else for(var g=1;g<c.length;g+=2)b.addToken(b,e.slice(f,f=c[g]),xf(c[g+1],b.cm.options))}function Ff(a,b){return 0==b.from.ch&&0==b.to.ch&&""==Kg(b.text)&&(!a.cm||a.cm.options.wholeLineUpdateBefore)}fu
 nction Gf(a,b,c,d){function e(a){return c?c[a]:null}function f(a,c,e){mf(a,c,e,d),ug(a,"change",a,b)}var g=b.from,h=b.to,i=b.text,j=Pf(a,g.line),k=Pf(a,h.line),l=Kg(i),m=e(i.length-1),n=h.line-g.line;if(Ff(a,b)){for(var o=0,p=[];o<i.length-1;++o)p.push(new lf(i[o],e(o),d));f(k,k.text,m),n&&a.remove(g.line,n),p.length&&a.insert(g.line,p)}else if(j==k)if(1==i.length)f(j,j.text.slice(0,g.ch)+l+j.text.slice(h.ch),m);else{for(var p=[],o=1;o<i.length-1;++o)p.push(new lf(i[o],e(o),d));p.push(new lf(l+j.text.slice(h.ch),m,d)),f(j,j.text.slice(0,g.ch)+i[0],e(0)),a.insert(g.line+1,p)}else if(1==i.length)f(j,j.text.slice(0,g.ch)+i[0]+k.text.slice(h.ch),e(0)),a.remove(g.line+1,n);else{f(j,j.text.slice(0,g.ch)+i[0],e(0)),f(k,l+k.text.slice(h.ch),m);for(var o=1,p=[];o<i.length-1;++o)p.push(new lf(i[o],e(o),d));n>1&&a.remove(g.line+1,n-1),a.insert(g.line+1,p)}ug(a,"change",a,b)}function Hf(a){this.lines=a,this.parent=null;for(var b=0,c=0;b<a.length;++b)a[b].parent=this,c+=a[b].height;this.height=c
 }function If(a){this.children=a;for(var b=0,c=0,d=0;d<a.length;++d){var e=a[d];b+=e.chunkSize(),c+=e.height,e.parent=this}this.size=b,this.height=c,this.parent=null}function Nf(a,b,c){function d(a,e,f){if(a.linked)for(var g=0;g<a.linked.length;++g){var h=a.linked[g];if(h.doc!=e){var i=f&&h.sharedHist;(!c||i)&&(b(h.doc,i),d(h.doc,a,i))}}}d(a,null,!0)}function Of(a,b){if(b.cm)throw new Error("This document is already in use.");a.doc=b,b.cm=a,C(a),y(a),a.options.lineWrapping||I(a),a.options.mode=b.modeOption,Pc(a)}function Pf(a,b){if(b-=a.first,0>b||b>=a.size)throw new Error("There is no line "+(b+a.first)+" in the document.");for(var c=a;!c.lines;)for(var d=0;;++d){var e=c.children[d],f=e.chunkSize();if(f>b){c=e;break}b-=f}return c.lines[b]}function Qf(a,b,c){var d=[],e=b.line;return a.iter(b.line,c.line+1,function(a){var f=a.text;e==c.line&&(f=f.slice(0,c.ch)),e==b.line&&(f=f.slice(b.ch)),d.push(f),++e}),d}function Rf(a,b,c){var d=[];return a.iter(b,c,function(a){d.push(a.text)}),d}f
 unction Sf(a,b){var c=b-a.height;if(c)for(var d=a;d;d=d.parent)d.height+=c}function Tf(a){if(null==a.parent)return null;for(var b=a.parent,c=Mg(b.lines,a),d=b.parent;d;b=d,d=d.parent)for(var e=0;d.children[e]!=b;++e)c+=d.children[e].chunkSize();return c+b.first}function Uf(a,b){var c=a.first;a:do{for(var d=0;d<a.children.length;++d){var e=a.children[d],f=e.height;if(f>b){a=e;continue a}b-=f,c+=e.chunkSize()}return c}while(!a.lines);for(var d=0;d<a.lines.length;++d){var g=a.lines[d],h=g.height;if(h>b)break;b-=h}return c+d}function Vf(a){a=af(a);for(var b=0,c=a.parent,d=0;d<c.lines.length;++d){var e=c.lines[d];if(e==a)break;b+=e.height}for(var f=c.parent;f;c=f,f=c.parent)for(var d=0;d<f.children.length;++d){var g=f.children[d];if(g==c)break;b+=g.height}return b}function Wf(a){var b=a.order;return null==b&&(b=a.order=Kh(a.text)),b}function Xf(a){this.done=[],this.undone=[],this.undoDepth=1/0,this.lastModTime=this.lastSelTime=0,this.lastOp=this.lastSelOp=null,this.lastOrigin=this.lastSe
 lOrigin=null,this.generation=this.maxGeneration=a||1}function Yf(a,b){var c={from:ob(b.from),to:Ld(b),text:Qf(a,b.from,b.to)};return dg(a,c,b.from.line,b.to.line+1),Nf(a,function(a){dg(a,c,b.from.line,b.to.line+1)},!0),c}function Zf(a){for(;a.length;){var b=Kg(a);if(!b.ranges)break;a.pop()}}function $f(a,b){return b?(Zf(a.done),Kg(a.done)):a.done.length&&!Kg(a.done).ranges?Kg(a.done):a.done.length>1&&!a.done[a.done.length-2].ranges?(a.done.pop(),Kg(a.done)):void 0}function _f(a,b,c,d){var e=a.history;e.undone.length=0;var g,f=+new Date;if((e.lastOp==d||e.lastOrigin==b.origin&&b.origin&&("+"==b.origin.charAt(0)&&a.cm&&e.lastModTime>f-a.cm.options.historyEventDelay||"*"==b.origin.charAt(0)))&&(g=$f(e,e.lastOp==d))){var h=Kg(g.changes);0==nb(b.from,b.to)&&0==nb(b.from,h.to)?h.to=Ld(b):g.changes.push(Yf(a,b))}else{var i=Kg(e.done);for(i&&i.ranges||cg(a.sel,e.done),g={changes:[Yf(a,b)],generation:e.generation},e.done.push(g);e.done.length>e.undoDepth;)e.done.shift(),e.done[0].ranges||e.d
 one.shift()}e.done.push(c),e.generation=++e.maxGeneration,e.lastModTime=e.lastSelTime=f,e.lastOp=e.lastSelOp=d,e.lastOrigin=e.lastSelOrigin=b.origin,h||sg(a,"historyAdded")}function ag(a,b,c,d){var e=b.charAt(0);return"*"==e||"+"==e&&c.ranges.length==d.ranges.length&&c.somethingSelected()==d.somethingSelected()&&new Date-a.history.lastSelTime<=(a.cm?a.cm.options.historyEventDelay:500)}function bg(a,b,c,d){var e=a.history,f=d&&d.origin;c==e.lastSelOp||f&&e.lastSelOrigin==f&&(e.lastModTime==e.lastSelTime&&e.lastOrigin==f||ag(a,f,Kg(e.done),b))?e.done[e.done.length-1]=b:cg(b,e.done),e.lastSelTime=+new Date,e.lastSelOrigin=f,e.lastSelOp=c,d&&d.clearRedo!==!1&&Zf(e.undone)}function cg(a,b){var c=Kg(b);c&&c.ranges&&c.equals(a)||b.push(a)}function dg(a,b,c,d){var e=b["spans_"+a.id],f=0;a.iter(Math.max(a.first,c),Math.min(a.first+a.size,d),function(c){c.markedSpans&&((e||(e=b["spans_"+a.id]={}))[f]=c.markedSpans),++f})}function eg(a){if(!a)return null;for(var c,b=0;b<a.length;++b)a[b].marke
 r.explicitlyCleared?c||(c=a.slice(0,b)):c&&c.push(a[b]);return c?c.length?c:null:a}function fg(a,b){var c=b["spans_"+a.id];if(!c)return null;for(var d=0,e=[];d<b.text.length;++d)e.push(eg(c[d]));return e}function gg(a,b,c){for(var d=0,e=[];d<a.length;++d){var f=a[d];if(f.ranges)e.push(c?rb.prototype.deepCopy.call(f):f);else{var g=f.changes,h=[];e.push({changes:h});for(var i=0;i<g.length;++i){var k,j=g[i];if(h.push({from:j.from,to:j.to,text:j.text}),b)for(var l in j)(k=l.match(/^spans_(\d+)$/))&&Mg(b,Number(k[1]))>-1&&(Kg(h)[l]=j[l],delete j[l])}}}return e}function hg(a,b,c,d){c<a.line?a.line+=d:b<a.line&&(a.line=b,a.ch=0)}function ig(a,b,c,d){for(var e=0;e<a.length;++e){var f=a[e],g=!0;if(f.ranges){f.copied||(f=a[e]=f.deepCopy(),f.copied=!0);for(var h=0;h<f.ranges.length;h++)hg(f.ranges[h].anchor,b,c,d),hg(f.ranges[h].head,b,c,d)}else{for(var h=0;h<f.changes.length;++h){var i=f.changes[h];if(c<i.from.line)i.from=mb(i.from.line+d,i.from.ch),i.to=mb(i.to.line+d,i.to.ch);else if(b<=i.t
 o.line){g=!1;break}}g||(a.splice(0,e+1),e=0)}}}function jg(a,b){var c=b.from.line,d=b.to.line,e=b.text.length-(d-c)-1;ig(a.done,c,d,e),ig(a.undone,c,d,e)}function mg(a){return null!=a.defaultPrevented?a.defaultPrevented:0==a.returnValue}function og(a){return a.target||a.srcElement}function pg(a){var b=a.which;return null==b&&(1&a.button?b=1:2&a.button?b=3:4&a.button&&(b=2)),p&&a.ctrlKey&&1==b&&(b=3),b}function ug(a,b){function f(a){return function(){a.apply(null,d)}}var c=a._handlers&&a._handlers[b];if(c){var e,d=Array.prototype.slice.call(arguments,2);yc?e=yc.delayedCallbacks:tg?e=tg:(e=tg=[],setTimeout(vg,0));for(var g=0;g<c.length;++g)e.push(f(c[g]))}}function vg(){var a=tg;tg=null;for(var b=0;b<a.length;++b)a[b]()}function wg(a,b,c){return sg(a,c||b.type,a,b),mg(b)||b.codemirrorIgnore}function xg(a){var b=a._handlers&&a._handlers.cursorActivity;if(b)for(var c=a.curOp.cursorActivityHandlers||(a.curOp.cursorActivityHandlers=[]),d=0;d<b.length;++d)-1==Mg(c,b[d])&&c.push(b[d])}funct
 ion yg(a,b){var c=a._handlers&&a._handlers[b];return c&&c.length>0}function zg(a){a.prototype.on=function(a,b){qg(this,a,b)},a.prototype.off=function(a,b){rg(this,a,b)}}function Fg(){this.id=null}function Hg(a,b,c){for(var d=0,e=0;;){var f=a.indexOf("	",d);-1==f&&(f=a.length);var g=f-d;if(f==a.length||e+g>=b)return d+Math.min(g,b-e);if(e+=f-d,e+=c-e%c,d=f+1,e>=b)return d}}function Jg(a){for(;Ig.length<=a;)Ig.push(Kg(Ig)+" ");return Ig[a]}function Kg(a){return a[a.length-1]}function Mg(a,b){for(var c=0;c<a.length;++c)if(a[c]==b)return c;return-1}function Ng(a,b){for(var c=[],d=0;d<a.length;d++)c[d]=b(a[d],d);return c}function Og(a,b){var c;if(Object.create)c=Object.create(a);else{var d=function(){};d.prototype=a,c=new d}return b&&Pg(b,c),c}function Pg(a,b,c){b||(b={});for(var d in a)!a.hasOwnProperty(d)||c===!1&&b.hasOwnProperty(d)||(b[d]=a[d]);return b}function Qg(a){var b=Array.prototype.slice.call(arguments,1);return function(){return a.apply(null,b)}}function Tg(a,b){return b?b.s
 ource.indexOf("\\w")>-1&&Sg(a)?!0:b.test(a):Sg(a)}function Ug(a){for(var b in a)if(a.hasOwnProperty(b)&&a[b])return!1;return!0}function Wg(a){return a.charCodeAt(0)>=768&&Vg.test(a)}function Xg(a,b,c,d){var e=document.createElement(a);if(c&&(e.className=c),d&&(e.style.cssText=d),"string"==typeof b)e.appendChild(document.createTextNode(b));else if(b)for(var f=0;f<b.length;++f)e.appendChild(b[f]);return e}function Zg(a){for(var b=a.childNodes.length;b>0;--b)a.removeChild(a.firstChild);return a}function $g(a,b){return Zg(a).appendChild(b)}function _g(a,b){if(a.contains)return a.contains(b);for(;b=b.parentNode;)if(b==a)return!0}function ah(){return document.activeElement}function bh(a){return new RegExp("\\b"+a+"\\b\\s*")}function eh(a,b){for(var c=a.split(" "),d=0;d<c.length;d++)c[d]&&!bh(c[d]).test(b)&&(b+=" "+c[d]);return b}function fh(a){if(document.body.getElementsByClassName)for(var b=document.body.getElementsByClassName("CodeMirror"),c=0;c<b.length;c++){var d=b[c].CodeMirror;d&&a
 (d)}}function hh(){gh||(ih(),gh=!0)}function ih(){var a;qg(window,"resize",function(){null==a&&(a=setTimeout(function(){a=null,kh=null,fh(dd)},100))}),qg(window,"blur",function(){fh(Id)})}function lh(a){if(null!=kh)return kh;var b=Xg("div",null,null,"width: 50px; height: 50px; overflow-x: scroll");return $g(a,b),b.offsetWidth&&(kh=b.offsetHeight-b.clientHeight),kh||0}function nh(a){if(null==mh){var b=Xg("span","\u200b");$g(a,Xg("span",[b,document.createTextNode("x")])),0!=a.firstChild.offsetHeight&&(mh=b.offsetWidth<=1&&b.offsetHeight>2&&!(d&&8>e))}return mh?Xg("span","\u200b"):Xg("span","\xa0",null,"display: inline-block; width: 1px; margin-right: -1px")}function ph(a){if(null!=oh)return oh;var b=$g(a,document.createTextNode("A\u062eA")),c=Yg(b,0,1).getBoundingClientRect();if(!c||c.left==c.right)return!1;var d=Yg(b,1,2).getBoundingClientRect();return oh=d.right-c.right<3}function uh(a){if(null!=th)return th;var b=$g(a,Xg("span","x")),c=b.getBoundingClientRect(),d=Yg(b,0,1).getBound
 ingClientRect();return th=Math.abs(c.left-d.left)>1}function wh(a,b,c,d){if(!a)return d(b,c,"ltr");for(var e=!1,f=0;f<a.length;++f){var g=a[f];(g.from<c&&g.to>b||b==c&&g.to==b)&&(d(Math.max(g.from,b),Math.min(g.to,c),1==g.level?"rtl":"ltr"),e=!0)}e||d(b,c,"ltr")}function xh(a){return a.level%2?a.to:a.from}function yh(a){return a.level%2?a.from:a.to}function zh(a){var b=Wf(a);return b?xh(b[0]):0}function Ah(a){var b=Wf(a);return b?yh(Kg(b)):a.text.length}function Bh(a,b){var c=Pf(a.doc,b),d=af(c);d!=c&&(b=Tf(d));var e=Wf(d),f=e?e[0].level%2?Ah(d):zh(d):0;return mb(b,f)}function Ch(a,b){for(var c,d=Pf(a.doc,b);c=$e(d);)d=c.find(1,!0).line,b=null;var e=Wf(d),f=e?e[0].level%2?zh(d):Ah(d):d.text.length;return mb(null==b?Tf(d):b,f)}function Dh(a,b){var c=Bh(a,b.line),d=Pf(a.doc,c.line),e=Wf(d);if(!e||0==e[0].level){var f=Math.max(0,d.text.search(/\S/)),g=b.line==c.line&&b.ch<=f&&b.ch;return mb(c.line,g?0:f)}return c}function Eh(a,b,c){var d=a[0].level;return b==d?!0:c==d?!1:c>b}function G
 h(a,b){Fh=null;for(var d,c=0;c<a.length;++c){var e=a[c];if(e.from<b&&e.to>b)return c;if(e.from==b||e.to==b){if(null!=d)return Eh(a,e.level,a[d].level)?(e.from!=e.to&&(Fh=d),c):(e.from!=e.to&&(Fh=c),d);d=c}}return d}function Hh(a,b,c,d){if(!d)return b+c;do b+=c;while(b>0&&Wg(a.text.charAt(b)));return b}function Ih(a,b,c,d){var e=Wf(a);if(!e)return Jh(a,b,c,d);for(var f=Gh(e,b),g=e[f],h=Hh(a,b,g.level%2?-c:c,d);;){if(h>g.from&&h<g.to)return h;if(h==g.from||h==g.to)retu

<TRUNCATED>

[11/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/databases.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/databases.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/databases.js
new file mode 100644
index 0000000..b76bca3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/databases.js
@@ -0,0 +1,457 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+import ENV from '../config/environment';
+
+export default Ember.Controller.extend({
+  databaseService: Ember.inject.service(constants.namingConventions.database),
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+
+  pageCount: 10,
+
+  previousSelectedDatabaseName : "" ,
+  selectedDatabase: Ember.computed.alias('databaseService.selectedDatabase'),
+  databases: Ember.computed.alias('databaseService.databases'),
+
+  tableSearchResults: Ember.Object.create(),
+
+  isDatabaseRefreshInProgress: false,
+
+  tableControls: [
+    {
+      icon: 'fa-list',
+      action: 'loadSampleData',
+      tooltip: Ember.I18n.t('tooltips.loadSample')
+    }
+  ],
+
+  panelIconActions: [
+    {
+      icon: 'fa-refresh',
+      action: 'refreshDatabaseExplorer',
+      tooltip: Ember.I18n.t('tooltips.refresh')
+    }
+  ],
+
+  tabs: [
+    Ember.Object.create({
+      name: Ember.I18n.t('titles.explorer'),
+      visible: true,
+      view: constants.namingConventions.databaseTree
+    }),
+    Ember.Object.create({
+      name: Ember.I18n.t('titles.results'),
+      view: constants.namingConventions.databaseSearch
+    })
+  ],
+
+  _handleError: function (error) {
+    this.get('notifyService').error(error);
+    this.set('isLoading', false);
+  },
+
+  setTablePageAvailability: function (database) {
+    var result;
+
+    if (database.get('hasNext')) {
+      result = true;
+    } else if (database.tables.length > database.get('visibleTables.length')) {
+      //if there are hidden tables
+      result = true;
+    }
+
+    database.set('canGetNextPage', result);
+  },
+
+  setColumnPageAvailability: function (table) {
+    var result;
+
+    if (table.get('hasNext')) {
+      result = true;
+    } else if (table.columns.length > table.get('visibleColumns.length')) {
+      //if there are hidden columns
+      result = true;
+    }
+
+    table.set('canGetNextPage', result);
+  },
+
+  selectedDatabaseChanged: function () {
+    var self = this;
+
+    this.resetSearch();
+
+    this.set('isLoading', true);
+
+    this.get('databaseService').getAllTables().then(function () {
+      self.set('isLoading', false);
+      self.set('previousSelectedDatabaseName',self.get('selectedDatabase').get('name'));
+      self.get('notifyService').info("Selected database : "+self.get('selectedDatabase').get('name'));
+    }, function (error) {
+      self.get('notifyService').pushError("Error while selecting database : "+self.get('selectedDatabase').get('name'),error.responseJSON.message+"\n"+error.responseJSON.trace);
+      self.get('databaseService').setDatabaseByName(self.get('previousSelectedDatabaseName'));
+      self.set('isLoading', false);
+    });
+  }.observes('selectedDatabase'),
+
+  getNextColumnPage: function (database, table) {
+    var self = this;
+
+    this.set('isLoading', true);
+
+    if (!table.columns) {
+      table.columns = [];
+      table.set('visibleColumns', []);
+    }
+
+    this.get('databaseService').getColumnsPage(database.get('name'), table).then(function (result) {
+      table.columns.pushObjects(result.columns);
+      table.get('visibleColumns').pushObjects(result.columns);
+      table.set('hasNext', result.hasNext);
+
+      self.setColumnPageAvailability(table);
+      self.set('isLoading', false);
+    }, function (err) {
+      self._handleError(err);
+    });
+  },
+
+  getNextTablePage: function (database) {
+    var self = this;
+
+    this.set('isLoading', true);
+
+    if (!database.tables) {
+      database.tables = [];
+      database.set('visibleTables', []);
+    }
+
+    this.get('databaseService').getTablesPage(database).then(function (result) {
+      database.tables.pushObjects(result.tables);
+      database.get('visibleTables').pushObjects(result.tables);
+      database.set('hasNext', result.hasNext);
+
+      self.setTablePageAvailability(database);
+      self.set('isLoading', false);
+    }, function (err) {
+      self._handleError(err);
+    });
+  },
+
+  getDatabases: function () {
+    var self = this;
+    var selectedDatabase = this.get('selectedDatabase.name') || 'default';
+
+    this.set('isDatabaseRefreshInProgress', true);
+
+    this.set('isLoading', true);
+
+    this.get('databaseService').getDatabases().then(function (databases) {
+      self.set('isLoading');
+      self.get('databaseService').setDatabaseByName(selectedDatabase);
+    }).catch(function (error) {
+      self._handleError(error);
+
+      if(error.status == 401) {
+         self.send('passwordLDAPDB');
+      }
+    }).finally(function() {
+      self.set('isDatabaseRefreshInProgress', false);
+    });
+  }.on('init'),
+
+  syncDatabases: function() {
+    this.set('isDatabaseRefreshInProgress', true);
+    var oldDatabaseNames = this.store.all('database').mapBy('name');
+    var self = this;
+    return this.get('databaseService').getDatabasesFromServer().then(function(data) {
+      // Remove the databases from store which are not in server
+      data.forEach(function(dbName) {
+        if(!oldDatabaseNames.contains(dbName)) {
+          self.store.createRecord('database', {
+            id: dbName,
+            name: dbName
+          });
+        }
+      });
+      // Add the databases in store which are new in server
+      oldDatabaseNames.forEach(function(dbName) {
+        if(!data.contains(dbName)) {
+          self.store.find('database', dbName).then(function(db) {
+            self.store.unloadRecord(db);
+          });
+        }
+      });
+    }).finally(function() {
+      self.set('isDatabaseRefreshInProgress', false);
+    });
+  },
+
+  initiateDatabaseSync: function() {
+    // This was required so that the unit test would not stall
+    if(ENV.environment !== "test") {
+      Ember.run.later(this, function() {
+        if (this.get('isDatabaseRefreshInProgress') === false) {
+          this.syncDatabases();
+          this.initiateDatabaseSync();
+        }
+      }, 15000);
+    }
+  }.on('init'),
+
+  resetSearch: function() {
+    var resultsTab = this.get('tabs').findBy('view', constants.namingConventions.databaseSearch);
+    var databaseExplorerTab = this.get('tabs').findBy('view', constants.namingConventions.databaseTree);
+    var tableSearchResults = this.get('tableSearchResults');
+    resultsTab.set('visible', false);
+    this.set('selectedTab', databaseExplorerTab);
+    this.set('tableSearchTerm', '');
+    this.set('columnSearchTerm', '');
+    tableSearchResults.set('tables', undefined);
+    tableSearchResults.set('hasNext', undefined);
+  },
+
+
+  actions: {
+    refreshDatabaseExplorer: function () {
+      if (this.get('isDatabaseRefreshInProgress') === false) {
+        this.getDatabases();
+        this.resetSearch();
+      } else {
+        console.log("Databases refresh is in progress. Skipping this request.");
+      }
+    },
+
+    passwordLDAPDB: function(){
+      var self = this,
+          defer = Ember.RSVP.defer();
+
+      this.send('openModal', 'modal-save', {
+        heading: "modals.authenticationLDAP.heading",
+        text:"",
+        type: "password",
+        defer: defer
+      });
+
+      defer.promise.then(function (text) {
+        // make a post call with the given ldap password.
+        var password = text;
+        var pathName = window.location.pathname;
+        var pathNameArray = pathName.split("/");
+        var hiveViewVersion = pathNameArray[3];
+        var hiveViewName = pathNameArray[4];
+        var ldapAuthURL = "/api/v1/views/HIVE/versions/"+ hiveViewVersion + "/instances/" + hiveViewName + "/jobs/auth";
+
+        $.ajax({
+          url: ldapAuthURL,
+          type: 'post',
+          headers: {'X-Requested-With': 'XMLHttpRequest', 'X-Requested-By': 'ambari'},
+          contentType: 'application/json',
+          data: JSON.stringify({ "password" : password}),
+          success: function( data, textStatus, jQxhr ){
+            console.log( "LDAP done: " + data );
+            self.getDatabases();
+            self.syncDatabases();
+          },
+          error: function( jqXhr, textStatus, errorThrown ){
+            console.log( "LDAP fail: " + errorThrown );
+            self.get('notifyService').error( "Wrong Credentials." );
+          }
+        });
+      });
+    },
+
+    loadSampleData: function (tableName, database) {
+      var self = this;
+      this.send('addQuery', Ember.I18n.t('titles.tableSample', { tableName: tableName }));
+
+      Ember.run.later(function () {
+        var query = constants.sampleDataQuery.fmt(tableName);
+
+        self.set('selectedDatabase', database);
+        self.send('executeQuery', constants.jobReferrer.sample, query);
+      });
+    },
+
+    getTables: function (dbName) {
+      var database = this.get('databases').findBy('name', dbName),
+          tables = database.tables,
+          pageCount = this.get('pageCount');
+
+      if (!tables) {
+        this.getNextTablePage(database);
+      } else {
+        database.set('visibleTables', tables.slice(0, pageCount));
+        this.setTablePageAvailability(database);
+      }
+    },
+
+    getColumns: function (tableName, database) {
+      var table = database.get('visibleTables').findBy('name', tableName),
+          pageCount = this.get('pageCount'),
+          columns = table.columns;
+
+      if (!columns) {
+        this.getNextColumnPage(database, table);
+      } else {
+        table.set('visibleColumns', columns.slice(0, pageCount));
+        this.setColumnPageAvailability(table);
+      }
+    },
+
+    showMoreTables: function (database) {
+      var tables = database.tables,
+          visibleTables = database.get('visibleTables'),
+          visibleCount = visibleTables.length;
+
+      if (!tables) {
+        this.getNextTablePage(database);
+      } else {
+        if (tables.length > visibleCount) {
+          visibleTables.pushObjects(tables.slice(visibleCount, visibleCount + this.get('pageCount')));
+          this.setTablePageAvailability(database);
+        } else {
+          this.getNextTablePage(database);
+        }
+      }
+    },
+
+    showMoreColumns: function (table, database) {
+      var columns = table.columns,
+          visibleColumns = table.get('visibleColumns'),
+          visibleCount = visibleColumns.length;
+
+      if (!columns) {
+        this.getNextColumnPage(database, table);
+      } else {
+        if (columns.length > visibleCount) {
+          visibleColumns.pushObjects(columns.slice(visibleCount, visibleCount + this.get('pageCount')));
+          this.setColumnPageAvailability(table);
+        } else {
+          this.getNextColumnPage(database, table);
+        }
+      }
+    },
+
+    searchTables: function (searchTerm) {
+      var self = this,
+          resultsTab = this.get('tabs').findBy('view', constants.namingConventions.databaseSearch),
+          tableSearchResults = this.get('tableSearchResults');
+
+      searchTerm = searchTerm ? searchTerm.toLowerCase() : '';
+
+      this.set('tablesSearchTerm', searchTerm);
+      resultsTab.set('visible', true);
+      this.set('selectedTab', resultsTab);
+      this.set('columnSearchTerm', '');
+      this.set('isLoading', true);
+
+      this.get('databaseService').getTablesPage(this.get('selectedDatabase'), searchTerm, true).then(function (result) {
+        tableSearchResults.set('tables', result.tables);
+        tableSearchResults.set('hasNext', result.hasNext);
+
+        self.set('isLoading', false);
+      }, function (err) {
+        self._handleError(err);
+      });
+    },
+
+    searchColumns: function (searchTerm) {
+      var self = this,
+          database = this.get('selectedDatabase'),
+          resultsTab = this.get('tabs').findBy('view', constants.namingConventions.databaseSearch),
+          tables = this.get('tableSearchResults.tables');
+
+      searchTerm = searchTerm ? searchTerm.toLowerCase() : '';
+
+      this.set('selectedTab', resultsTab);
+
+      this.set('isLoading', true);
+
+      tables.forEach(function (table) {
+        self.get('databaseService').getColumnsPage(database.get('name'), table, searchTerm, true).then(function (result) {
+          table.set('columns', result.columns);
+          table.set('hasNext', result.hasNext);
+
+          if (tables.indexOf(table) === tables.get('length') -1) {
+            self.set('isLoading', false);
+          }
+        }, function (err) {
+          self._handleError(err);
+        });
+      });
+    },
+
+    showMoreResultTables: function () {
+      var self = this,
+          database = this.get('selectedDatabase'),
+          tableSearchResults = this.get('tableSearchResults'),
+          searchTerm = this.get('tableSearchTerm');
+
+      this.set('isLoading', true);
+
+      this.get('databaseService').getTablesPage(database, searchTerm).then(function (tablesResult) {
+        var tables = tableSearchResults.get('tables');
+        var shouldGetColumns = tables.any(function (table) {
+          return table.get('columns.length') > 0;
+        });
+
+        tables.pushObjects(tablesResult.tables);
+        tableSearchResults.set('hasNext', tablesResult.hasNext);
+
+        //if user has already searched for columns for the previously loaded tables,
+        //load the columns search results for the newly loaded tables.
+        if (shouldGetColumns) {
+          tablesResult.tables.forEach(function (table) {
+            self.get('databaseService').getColumnsPage(database.get('name'), table, self.get('columnSearchTerm'), true).then(function (result) {
+              table.set('columns', result.columns);
+              table.set('hasNext', result.hasNext);
+
+              if (tablesResult.tables.indexOf(table) === tablesResult.tables.get('length') -1) {
+                self.set('isLoading', false);
+              }
+            }, function (err) {
+              self._handleError(err);
+            });
+          });
+        } else {
+          self.set('isLoading', false);
+        }
+      }, function (err) {
+        self._handleError(err);
+      });
+    },
+
+    showMoreResultColumns: function (table) {
+      var self = this;
+
+      this.set('isLoading', true);
+
+      this.get('databaseService').getColumnsPage(this.get('selectedDatabase.name'), table, this.get('columnSearchTerm')).then(function (result) {
+        table.get('columns').pushObjects(result.columns);
+        table.set('hasNext', result.hasNext);
+
+        self.set('isLoading', false);
+      }, function (err) {
+        self._handleError(err);
+      });
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/history.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/history.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/history.js
new file mode 100644
index 0000000..8c4ed2f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/history.js
@@ -0,0 +1,172 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import FilterableMixin from 'hive/mixins/filterable';
+import constants from 'hive/utils/constants';
+
+export default Ember.ArrayController.extend(FilterableMixin, {
+  jobService: Ember.inject.service('job'),
+  fileService: Ember.inject.service('file'),
+
+  sortAscending: false,
+  sortProperties: ['dateSubmittedTimestamp'],
+
+  init: function () {
+    var oneMonthAgo = new Date();
+    oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
+
+    this._super();
+
+    this.set('columns', Ember.ArrayProxy.create({ content: Ember.A([
+      Ember.Object.create({
+        caption: 'columns.title',
+        property: 'title',
+        link: constants.namingConventions.subroutes.historyQuery
+      }),
+      Ember.Object.create({
+        caption: 'columns.status',
+        property: 'status'
+      }),
+      Ember.Object.create({
+        caption: 'columns.date',
+        property: 'dateSubmittedTimestamp',
+        dateRange: Ember.Object.create({
+          min: oneMonthAgo,
+          max: new Date()
+        })
+      }),
+      Ember.Object.create({
+        caption: 'columns.duration',
+        property: 'duration',
+        numberRange: Ember.Object.create({
+          min: 0,
+          max: 10,
+          units: 'sec'
+        })
+      })
+    ])}));
+  },
+
+  model: function () {
+    return this.filter(this.get('history'));
+  }.property('history', 'filters.@each'),
+
+  updateIntervals: function () {
+    var durationColumn;
+    var maxDuration;
+    var minDuration;
+
+    if (this.get('columns')) {
+      durationColumn = this.get('columns').find(function (column) {
+        return column.get('caption') === 'columns.duration';
+      });
+
+      var items = this.get('history').map(function (item) {
+        return item.get(durationColumn.get('property'));
+      });
+
+      minDuration = items.length ? Math.min.apply(Math, items) : 0;
+      maxDuration = items.length ? Math.max.apply(Math, items) : 60; //Default 1 min
+
+      durationColumn.set('numberRange.min', minDuration);
+      durationColumn.set('numberRange.max', maxDuration);
+    }
+  }.observes('history'),
+
+  updateDateRange: function () {
+    var dateColumn;
+    var maxDate;
+    var minDate;
+
+    if (this.get('columns')) {
+      dateColumn = this.get('columns').find(function (column) {
+        return column.get('caption') === 'columns.date';
+      });
+
+      var items = this.get('history').map(function (item) {
+        return item.get(dateColumn.get('property'));
+      });
+
+      minDate = items.length ? Math.min.apply(Math, items) : new Date();
+      maxDate = items.length ? Math.max.apply(Math, items) : new Date();
+
+      dateColumn.set('dateRange.min', minDate);
+      dateColumn.set('dateRange.max', maxDate);
+    }
+  }.observes('history'),
+
+  filterBy: function (filterProperty, filterValue, exactMatch) {
+    var column = this.get('columns').find(function (column) {
+      return column.get('property') === filterProperty;
+    });
+
+    if (column) {
+      column.set('filterValue', filterValue, exactMatch);
+    } else {
+      this.updateFilters(filterProperty, filterValue, exactMatch);
+    }
+  },
+
+  actions: {
+    sort: function (property) {
+      //if same column has been selected, toggle flag, else default it to true
+      if (this.get('sortProperties').objectAt(0) === property) {
+        this.set('sortAscending', !this.get('sortAscending'));
+      } else {
+        this.set('sortAscending', true);
+        this.set('sortProperties', [ property ]);
+      }
+    },
+
+    interruptJob: function (job) {
+      this.get('jobService').stopJob(job);
+    },
+
+    loadFile: function (job) {
+      this.get('fileService').loadFile(job.get('queryFile')).then(function (file) {
+        job.set('file', file);
+      });
+    },
+
+    clearFilters: function () {
+      var columns = this.get('columns');
+
+      if (columns) {
+        columns.forEach(function (column) {
+          var filterValue = column.get('filterValue');
+          var rangeFilter;
+
+          if (filterValue) {
+            if (typeof filterValue === 'string') {
+              column.set('filterValue');
+            } else {
+              rangeFilter = column.get('numberRange') || column.get('dateRange');
+
+              rangeFilter.set('from', rangeFilter.get('min'));
+              rangeFilter.set('to', rangeFilter.get('max'));
+            }
+          }
+        });
+      }
+
+      //call clear filters from Filterable mixin
+      this.clearFilters();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index.js
new file mode 100644
index 0000000..9584508
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index.js
@@ -0,0 +1,731 @@
+/** * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+import utils from 'hive/utils/functions';
+
+export default Ember.Controller.extend({
+  jobService: Ember.inject.service(constants.namingConventions.job),
+  jobProgressService: Ember.inject.service(constants.namingConventions.jobProgress),
+  databaseService: Ember.inject.service(constants.namingConventions.database),
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+  session: Ember.inject.service(constants.namingConventions.session),
+  settingsService: Ember.inject.service(constants.namingConventions.settings),
+
+  openQueries   : Ember.inject.controller(constants.namingConventions.openQueries),
+  udfs          : Ember.inject.controller(constants.namingConventions.udfs),
+  logs          : Ember.inject.controller(constants.namingConventions.jobLogs),
+  results       : Ember.inject.controller(constants.namingConventions.jobResults),
+  explain       : Ember.inject.controller(constants.namingConventions.jobExplain),
+  settings      : Ember.inject.controller(constants.namingConventions.settings),
+  visualExplain : Ember.inject.controller(constants.namingConventions.visualExplain),
+  tezUI         : Ember.inject.controller(constants.namingConventions.tezUI),
+
+  selectedDatabase: Ember.computed.alias('databaseService.selectedDatabase'),
+  isDatabaseExplorerVisible: true,
+  canKillSession: Ember.computed.and('model.sessionTag', 'model.sessionActive'),
+
+  queryProcessTabs: [
+    Ember.Object.create({
+      name: Ember.I18n.t('menus.logs'),
+      path: constants.namingConventions.subroutes.jobLogs
+    }),
+    Ember.Object.create({
+      name: Ember.I18n.t('menus.results'),
+      path: constants.namingConventions.subroutes.jobResults
+    }),
+    Ember.Object.create({
+      name: Ember.I18n.t('menus.explain'),
+      path: constants.namingConventions.subroutes.jobExplain
+    })
+  ],
+
+  queryPanelActions: [
+    Ember.Object.create({
+      icon: 'fa-expand',
+      action: 'toggleDatabaseExplorerVisibility',
+      tooltip: Ember.I18n.t('tooltips.expand')
+    })
+  ],
+
+  init: function () {
+    this._super();
+
+    // initialize queryParams with an empty array
+    this.set('queryParams', Ember.ArrayProxy.create({ content: Ember.A([]) }));
+
+    this.set('queryProcessTabs', Ember.ArrayProxy.create({ content: Ember.A([
+      Ember.Object.create({
+        name: Ember.I18n.t('menus.logs'),
+        path: constants.namingConventions.subroutes.jobLogs
+      }),
+      Ember.Object.create({
+        name: Ember.I18n.t('menus.results'),
+        path: constants.namingConventions.subroutes.jobResults
+      }),
+      Ember.Object.create({
+        name: Ember.I18n.t('menus.explain'),
+        path: constants.namingConventions.subroutes.jobExplain
+      })
+    ])}));
+
+    this.set('queryPanelActions', Ember.ArrayProxy.create({ content: Ember.A([
+      Ember.Object.create({
+        icon: 'fa-expand',
+        action: 'toggleDatabaseExplorerVisibility',
+        tooltip: Ember.I18n.t('tooltips.expand')
+      })
+    ])}));
+  },
+
+  canExecute: function () {
+    var isModelRunning = this.get('model.isRunning');
+    var hasParams = this.get('queryParams.length');
+
+    if (isModelRunning) {
+      return false;
+    }
+
+    if (hasParams) {
+      // all param have values?
+      return this.get('queryParams').every(function (param) { return param.value; });
+    }
+
+    return true;
+  }.property('model.isRunning', 'queryParams.@each.value'),
+
+  currentQueryObserver: function () {
+    var query = this.get('openQueries.currentQuery.fileContent'),
+        param,
+        updatedParams = [],
+        currentParams = this.get('queryParams'),
+        paramRegExp = /\$\w+/ig,
+        paramNames = query.match(paramRegExp) || [];
+
+    paramNames = paramNames.uniq();
+
+    paramNames.forEach(function (name) {
+      param = currentParams.findBy('name', name);
+      if (param) {
+        updatedParams.push(param);
+      } else {
+        updatedParams.push({ name: name, value: "" });
+      }
+    });
+
+    currentParams.setObjects(updatedParams);
+
+    this.set('visualExplain.shouldChangeGraph', true);
+  }.observes('openQueries.currentQuery.fileContent'),
+
+  _executeQuery: function (referrer, shouldExplain, shouldGetVisualExplain) {
+    var queryId,
+        query,
+        finalQuery,
+        job,
+        defer = Ember.RSVP.defer(),
+        originalModel = this.get('model');
+
+    job = this.store.createRecord(constants.namingConventions.job, {
+      title: originalModel.get('title'),
+      sessionTag: originalModel.get('sessionTag'),
+      dataBase: this.get('selectedDatabase.name'),
+      referrer: referrer
+    });
+
+    if (!shouldGetVisualExplain) {
+      originalModel.set('isRunning', true);
+    }
+
+     //if it's a saved query / history entry set the queryId
+    if (!originalModel.get('isNew')) {
+      queryId = originalModel.get('constructor.typeKey') === constants.namingConventions.job ?
+                originalModel.get('queryId') :
+                originalModel.get('id');
+
+      job.set('queryId', queryId);
+    }
+
+    query = this.get('openQueries').getQueryForModel(originalModel);
+
+    query = this.buildQuery(query, shouldExplain, shouldGetVisualExplain);
+
+
+    // Condition for no query.
+    if(query === ';') {
+      originalModel.set('isEmptyQuery', true);
+      originalModel.set('isRunning', false);
+      defer.reject({
+        message: 'No query to process.'
+      });
+      return defer.promise;
+    }
+
+    // for now we won't support multiple queries
+    // buildQuery will return false it multiple queries
+    // are selected
+    if (!query) {
+      originalModel.set('isRunning', false);
+      defer.reject({
+        message: 'Running multiple queries is not supported.'
+      });
+
+      return defer.promise;
+    }
+
+    finalQuery = query;
+    finalQuery = this.bindQueryParams(finalQuery);
+    finalQuery = this.prependGlobalSettings(finalQuery, job);
+
+    job.set('forcedContent', finalQuery);
+
+    if (shouldGetVisualExplain) {
+      return this.getVisualExplainJson(job, originalModel);
+    }
+
+    return this.createJob(job, originalModel);
+  },
+
+  getVisualExplainJson: function (job, originalModel) {
+    var self = this;
+    var defer = Ember.RSVP.defer();
+
+    job.save().then(function () {
+      self.get('results').getResultsJson(job).then(function (json) {
+        defer.resolve(json);
+      }, function (err) {
+        defer.reject(err);
+      });
+    }, function (err) {
+      defer.reject(err);
+    });
+
+    return defer.promise;
+  },
+
+  createJob: function (job, originalModel) {
+    var defer = Ember.RSVP.defer(),
+        self = this,
+        openQueries = this.get('openQueries');
+
+    var handleError = function (err) {
+      self.set('jobSaveSucceeded');
+      originalModel.set('isRunning', undefined);
+      defer.reject(err);
+
+      if(err.status == 401) {
+          self.send('passwordLDAP', job, originalModel);
+      }
+
+    };
+
+    job.save().then(function () {
+      //convert tab for current model since the execution will create a new job, and navigate to the new job route.
+      openQueries.convertTabToJob(originalModel, job).then(function () {
+        self.get('jobProgressService').setupProgress(job);
+        self.set('jobSaveSucceeded', true);
+
+        //reset flag on the original model
+        originalModel.set('isRunning', undefined);
+
+        defer.resolve(job);
+      }, function (err) {
+        handleError(err);
+      });
+    }, function (err) {
+      handleError(err);
+    });
+
+    return defer.promise;
+  },
+
+  prependGlobalSettings: function (query, job) {
+    var jobGlobalSettings = job.get('globalSettings');
+    var currentGlobalSettings = this.get('settingsService').getSettings();
+
+    // remove old globals
+    if (jobGlobalSettings) {
+      query.replace(jobGlobalSettings, '');
+    }
+
+    job.set('globalSettings', currentGlobalSettings);
+    query = currentGlobalSettings + query;
+
+    return query;
+  },
+
+  buildQuery: function (query, shouldExplain, shouldGetVisualExplain) {
+    var selections = this.get('openQueries.highlightedText'),
+        isQuerySelected = selections && selections[0] !== "",
+        queryContent = query ? query.get('fileContent') : '',
+        queryComponents = this.extractComponents(queryContent),
+        finalQuery = '',
+        queries = null;
+
+    if (isQuerySelected) {
+      queryComponents.queryString = selections.join('');
+    }
+
+    queries = queryComponents.queryString.split(';');
+    queries = queries.filter(Boolean);
+
+    var queriesLength = queries.length;
+
+    queries = queries.map(function (q, index) {
+      var newQuery = q.replace(/explain formatted|explain/gi, '');
+      return newQuery;
+    });
+
+    var lastQuery = queries[queriesLength - 1];
+
+    if(!Ember.isNone(lastQuery) && shouldExplain) {
+      if (shouldGetVisualExplain) {
+        lastQuery = constants.namingConventions.explainFormattedPrefix + lastQuery;
+      } else {
+        lastQuery = constants.namingConventions.explainPrefix + lastQuery;
+      }
+      queries[queriesLength - 1] = lastQuery;
+    }
+
+    if (queryComponents.files.length) {
+      finalQuery += queryComponents.files.join("\n") + "\n\n";
+    }
+
+    if (queryComponents.udfs.length) {
+      finalQuery += queryComponents.udfs.join("\n") + "\n\n";
+    }
+
+    finalQuery += queries.join(";") + ";";
+    return finalQuery.trim();
+  },
+
+  bindQueryParams: function (query) {
+    var params = this.get('queryParams');
+
+    if (!params.get('length')) {
+      return query;
+    }
+
+    params.forEach(function (param) {
+      query = query.split(param.name).join(param.value);
+    });
+
+    return query;
+  },
+
+  displayJobTabs: function () {
+    return this.get('content.constructor.typeKey') === constants.namingConventions.job &&
+           utils.isInteger(this.get('content.id')) &&
+           this.get('jobSaveSucceeded');
+  }.property('content', 'jobSaveSucceeded'),
+
+  databasesOrModelChanged: function () {
+    this.get('databaseService').setDatabaseByName(this.get('content.dataBase'));
+  }.observes('databaseService.databases', 'content'),
+
+  selectedDatabaseChanged: function () {
+    this.set('content.dataBase', this.get('selectedDatabase.name'));
+  }.observes('selectedDatabase'),
+
+  modelChanged: function () {
+    var self = this;
+    var content = this.get('content');
+    var openQueries = this.get('openQueries');
+
+    this.set('jobSaveSucceeded', true);
+
+    //update open queries list when current query model changes
+    openQueries.update(content).then(function (isExplainedQuery) {
+      var newId = content.get('id');
+      var tab = openQueries.getTabForModel(content);
+
+      //if not an ATS job
+      if (content.get('constructor.typeKey') === constants.namingConventions.job && utils.isInteger(newId)) {
+        self.get('queryProcessTabs').forEach(function (queryTab) {
+          queryTab.set('id', newId);
+        });
+
+        if (isExplainedQuery) {
+          self.set('explain.content', content);
+        } else {
+          self.set('logs.content', content);
+          self.set('results.content', content);
+        }
+
+        self.setExplainVisibility(isExplainedQuery);
+
+        self.transitionToRoute(tab.get('subroute'));
+      }
+    });
+  }.observes('content'),
+
+  csvUrl: function () {
+    if (this.get('content.constructor.typeKey') !== constants.namingConventions.job) {
+      return;
+    }
+
+    if (!utils.insensitiveCompare(this.get('content.status'), constants.statuses.succeeded)) {
+      return;
+    }
+
+    var url = this.container.lookup('adapter:application').buildURL();
+    url += '/' + constants.namingConventions.jobs + '/' + this.get('content.id');
+    url += '/results/csv';
+
+    return url;
+  }.property('content'),
+
+  downloadMenu: function () {
+    var items = [];
+    var tabs = this.get('queryProcessTabs');
+    var isResultsTabVisible = tabs.findBy('path', constants.namingConventions.subroutes.jobResults).get('visible');
+
+    if (utils.insensitiveCompare(this.get('content.status'), constants.statuses.succeeded) && isResultsTabVisible) {
+      items.push({
+        title: Ember.I18n.t('buttons.saveHdfs'),
+        action: 'saveToHDFS'
+      });
+
+      if (this.get('csvUrl')) {
+        items.push(
+          Ember.Object.create({
+            title: Ember.I18n.t('buttons.saveCsv'),
+            action: 'downloadAsCSV'
+          })
+        );
+      }
+    }
+
+    return items.length ? items : null;
+  }.property('content.status', 'queryProcessTabs.@each.visible'),
+
+  extractComponents: function (queryString) {
+    var components = {};
+
+    var udfRegEx = new RegExp("(" + constants.namingConventions.udfInsertPrefix + ").+", "ig");
+    var fileRegEx = new RegExp("(" + constants.namingConventions.fileInsertPrefix + ").+", "ig");
+
+    components.udfs         = queryString.match(udfRegEx) || [];
+    components.files        = queryString.match(fileRegEx) || [];
+    components.queryString  = queryString.replace(udfRegEx, "").replace(fileRegEx, "").trim();
+
+    return components;
+  },
+
+  saveToHDFS: function (path) {
+    var job = this.get('content');
+
+    if (!utils.insensitiveCompare(job.get('status'), constants.statuses.succeeded)) {
+      return;
+    }
+
+    var self = this;
+
+    var file = path + ".csv";
+    var url = this.container.lookup('adapter:application').buildURL();
+    url +=  "/jobs/" + job.get('id') + "/results/csv/saveToHDFS";
+
+    Ember.$.getJSON(url, {
+        commence: true,
+        file: file
+    }).then(function (response) {
+      self.pollSaveToHDFS(response);
+    }, function (error) {
+      self.get('notifyService').error(error);
+    });
+  },
+
+  pollSaveToHDFS: function (data) {
+    var self = this;
+    var url = this.container.lookup('adapter:application').buildURL();
+    url += "/jobs/" + data.jobId + "/results/csv/saveToHDFS";
+
+    Ember.run.later(function () {
+      Ember.$.getJSON(url).then(function (response) {
+        if (!utils.insensitiveCompare(response.status, constants.results.statuses.terminated)) {
+          self.pollSaveToHDFS(response);
+        } else {
+          self.set('content.isRunning', false);
+        }
+      }, function (error) {
+        self.get('notifyService').error(error);
+      });
+    }, 2000);
+  },
+
+  setExplainVisibility: function (show) {
+    var tabs = this.get('queryProcessTabs');
+
+    tabs.findBy('path', constants.namingConventions.subroutes.jobExplain).set('visible', show);
+    tabs.findBy('path', constants.namingConventions.subroutes.jobLogs).set('visible', !show);
+    tabs.findBy('path', constants.namingConventions.subroutes.jobResults).set('visible', !show);
+  },
+
+  queryProcessTitle: function () {
+    return Ember.I18n.t('titles.query.process') + ' (' + Ember.I18n.t('titles.query.status') + this.get('content.status') + ')';
+  }.property('content.status'),
+
+  updateSessionStatus: function() {
+    this.get('session').updateSessionStatus(this.get('model'));
+  }.observes('model', 'model.status'),
+
+  actions: {
+    passwordLDAP: function(){
+      var job = arguments[0],
+            originalModel = arguments[1],
+            self = this,
+            defer = Ember.RSVP.defer();
+
+        this.send('openModal', 'modal-save', {
+          heading: "modals.authenticationLDAP.heading",
+          text:"",
+          type: "password",
+          defer: defer
+        });
+
+        defer.promise.then(function (text) {
+            // make a post call with the given ldap password.
+            var password = text;
+            var pathName = window.location.pathname;
+            var pathNameArray = pathName.split("/");
+            var hiveViewVersion = pathNameArray[3];
+            var hiveViewName = pathNameArray[4];
+            var ldapAuthURL = "/api/v1/views/HIVE/versions/"+ hiveViewVersion + "/instances/" + hiveViewName + "/jobs/auth";
+
+            $.ajax({
+                url: ldapAuthURL,
+                type: 'post',
+                headers: {'X-Requested-With': 'XMLHttpRequest', 'X-Requested-By': 'ambari'},
+                contentType: 'application/json',
+                data: JSON.stringify({ "password" : password}),
+                success: function( data, textStatus, jQxhr ){
+
+                  self.get('databaseService').getDatabases().then(function (databases) {
+                    var selectedDatabase = self.get('databaseService.selectedDatabase.name') || 'default';
+                    self.get('databaseService').setDatabaseByName( selectedDatabase);
+                    return self.send('executeQuery', 'job', self.get('openQueries.currentQuery.fileContent') );
+                  }).catch(function (error) {
+                    self.get('notifyService').error( "Error in accessing databases." );
+                  });
+
+                },
+                error: function( jqXhr, textStatus, errorThrown ){
+                    console.log( "LDAP fail: " + errorThrown );
+                    self.get('notifyService').error( "Wrong Credentials." );
+                }
+            });
+
+          });
+    },
+
+    stopCurrentJob: function () {
+      this.get('jobService').stopJob(this.get('model'));
+    },
+
+    saveToHDFS: function () {
+      var self = this,
+          defer = Ember.RSVP.defer();
+
+      this.send('openModal', 'modal-save', {
+        heading: "modals.download.hdfs",
+        text: this.get('content.title') + '_' + this.get('content.id'),
+        defer: defer
+      });
+
+      defer.promise.then(function (text) {
+        self.set('content.isRunning', true);
+        self.saveToHDFS(text);
+      });
+    },
+
+    downloadAsCSV: function () {
+      var self = this,
+          defer = Ember.RSVP.defer();
+
+      this.send('openModal', 'modal-save', {
+        heading: "modals.download.csv",
+        text: this.get('content.title'),
+        defer: defer
+      });
+
+      defer.promise.then(function (text) {
+        // download file ...
+        var urlString = "%@/?fileName=%@.csv";
+        var url = self.get('csvUrl');
+        url = urlString.fmt(url, text);
+        window.open(url);
+      });
+    },
+
+    insertUdf: function (item) {
+      var query = this.get('openQueries.currentQuery');
+
+      var queryString = query.get('fileContent');
+
+      var newUdf = constants.namingConventions.udfInsertPrefix + item.get('name') + " as '" + item.get('classname') + "';";
+      var newFileResource = item.get('fileResource.path');
+
+      if (item.get('fileResource.path')) {
+        newFileResource = constants.namingConventions.fileInsertPrefix + item.get('fileResource.path') + ";";
+      }
+
+      var components = this.extractComponents(queryString);
+
+      if (!components.files.contains(newFileResource) && newFileResource) {
+        components.files.push(newFileResource);
+      }
+
+      if (!components.udfs.contains(newUdf)) {
+        components.udfs.push(newUdf);
+      }
+
+      var updatedContent = components.files.join("\n") + "\n\n";
+      updatedContent += components.udfs.join("\n") + "\n\n";
+      updatedContent += components.queryString;
+
+      query.set('fileContent', updatedContent);
+    },
+
+    addQuery: (function () {
+      var idCounter = 0;
+
+      return function (workSheetName) {
+        var model = this.store.createRecord(constants.namingConventions.savedQuery, {
+          dataBase: this.get('selectedDatabase.name'),
+          title: workSheetName ? workSheetName : Ember.I18n.t('titles.query.tab'),
+          queryFile: '',
+          id: 'fixture_' + idCounter
+        });
+
+        if (idCounter && !workSheetName) {
+          model.set('title', model.get('title') + ' (' + idCounter + ')');
+        }
+
+        idCounter++;
+
+        this.transitionToRoute(constants.namingConventions.subroutes.savedQuery, model);
+      };
+    }()),
+
+    saveQuery: function () {
+      //case 1. Save a new query from a new query tab -> route changes to new id
+      //case 2. Save a new query from an existing query tab -> route changes to new id
+      //case 3. Save a new query from a job tab -> route doesn't change
+      //case 4. Update an existing query tab. -> route doesn't change
+
+      var self = this,
+          defer = Ember.RSVP.defer(),
+          currentQuery = this.get('openQueries.currentQuery');
+
+      this.set('model.dataBase', this.get('selectedDatabase.name'));
+
+      this.send('openModal', 'modal-save-query', {
+        heading: 'modals.save.heading',
+        message: 'modals.save.overwrite',
+        text: this.get('content.title'),
+        content: this.get('content'),
+        defer: defer
+      });
+
+      defer.promise.then(function (result) {
+        // we need to update the original model
+        // because when this is executed
+        // it sets the title from the original model
+        self.set('model.title', result.get('text'));
+
+        if (result.get('overwrite')) {
+          self.get('openQueries').save(self.get('content'), null, true, result.get('text')).then(function () {
+            self.get('notifyService').success(Ember.I18n.t('alerts.success.query.update'));
+          });
+        } else {
+          self.get('openQueries').save(self.get('content'), null, false, result.get('text')).then(function (newId) {
+            self.get('notifyService').success(Ember.I18n.t('alerts.success.query.save'));
+
+            if (self.get('model.constructor.typeKey') !== constants.namingConventions.job) {
+              self.transitionToRoute(constants.namingConventions.subroutes.savedQuery, newId);
+            }
+          });
+        }
+      });
+    },
+
+    executeQuery: function (referrer, query) {
+      var self = this;
+
+      var isExplainQuery = (self.get('openQueries.currentQuery.fileContent').toUpperCase().trim().indexOf(constants.namingConventions.explainPrefix) === 0);
+
+      if(isExplainQuery){
+        self.send('explainQuery');
+        return;
+      }
+
+      var subroute;
+
+      if (query) {
+        this.set('openQueries.currentQuery.fileContent', query);
+      }
+
+      referrer = referrer || constants.jobReferrer.job;
+
+      this._executeQuery(referrer).then(function (job) {
+        if (job.get('status') !== constants.statuses.succeeded) {
+          subroute = constants.namingConventions.subroutes.jobLogs;
+        } else {
+          subroute = constants.namingConventions.subroutes.jobResults;
+        }
+
+        self.get('openQueries').updateTabSubroute(job, subroute);
+        self.get('notifyService').success(Ember.I18n.t('alerts.success.query.execution'));
+        self.transitionToRoute(constants.namingConventions.subroutes.historyQuery, job.get('id'));
+      }, function (error) {
+        self.get('notifyService').error(error);
+      });
+    },
+
+    explainQuery: function () {
+      var self = this;
+
+      this._executeQuery(constants.jobReferrer.explain, true).then(function (job) {
+        self.get('openQueries').updateTabSubroute(job, constants.namingConventions.subroutes.jobExplain);
+
+        self.transitionToRoute(constants.namingConventions.subroutes.historyQuery, job.get('id'));
+      }, function (error) {
+        self.get('notifyService').error(error);
+      });
+    },
+
+    toggleDatabaseExplorerVisibility: function () {
+      this.toggleProperty('isDatabaseExplorerVisible');
+    },
+
+    killSession: function() {
+      var self = this;
+      var model = this.get('model');
+
+      this.get('session').killSession(model)
+        .catch(function (response) {
+          if ([200, 404].contains(response.status)) {
+            model.set('sessionActive', false);
+            self.notify.success(Ember.I18n.t('alerts.success.sessions.deleted'));
+          } else {
+            self.notify.error(response);
+          }
+        });
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js
new file mode 100644
index 0000000..20092e2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/explain.js
@@ -0,0 +1,134 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+import utils from 'hive/utils/functions';
+
+export default Ember.ObjectController.extend({
+  cachedExplains: [],
+
+  clearCachedExplainSet: function (jobId) {
+    var existingJob = this.get('cachedExplains').findBy('id', jobId);
+
+    if (existingJob) {
+      this.set('cachedExplains', this.get('cachedExplains').without(existingJob));
+    }
+  },
+
+  initExplain: function () {
+    var cachedExplain;
+
+    cachedExplain = this.get('cachedExplains').findBy('id', this.get('content.id'));
+
+    if (cachedExplain) {
+      this.formatExplainResults(cachedExplain);
+    } else {
+      this.getExplain(true);
+    }
+  }.observes('content'),
+
+  getExplain: function (firstPage, rows) {
+    var self = this;
+    var url = this.container.lookup('adapter:application').buildURL();
+    url += '/' + constants.namingConventions.jobs + '/' + this.get('content.id') + '/results';
+
+    if (firstPage) {
+      url += '?first=true';
+    }
+
+    this.get('content').reload().then(function () {
+      Ember.$.getJSON(url).then(function (data) {
+        var explainSet;
+
+        //if rows from a previous page read exist, prepend them
+        if (rows) {
+          data.rows.unshiftObjects(rows);
+        }
+
+        if (!data.hasNext) {
+          explainSet = self.get('cachedExplains').pushObject(Ember.Object.create({
+            id: self.get('content.id'),
+            explain: data
+          }));
+
+          self.set('content.explain', explainSet);
+
+          self.formatExplainResults(explainSet);
+        } else {
+          self.getExplain(false, data.rows);
+        }
+      });
+    })
+  },
+
+  formatExplainResults: function (explainSet) {
+    var formatted = [],
+        currentNode,
+        currentNodeWhitespace,
+        previousNode,
+        getLeadingWhitespacesCount = function (str) {
+          return str.replace(utils.regexes.whitespaces, '$1').length;
+        };
+
+    explainSet = explainSet
+                 .get('explain.rows')
+                 .map(function (row) {
+                    return row[0];
+                  })
+                 .filter(Boolean)
+                 .map(function (str) {
+                    return {
+                      text: str,
+                      parentNode: null,
+                      contents: []
+                    };
+                  });
+
+    for (var i = 0; i < explainSet.length; i++) {
+      currentNode = explainSet[i];
+      previousNode = explainSet[i-1];
+
+      if (i > 0) {
+        currentNodeWhitespace = getLeadingWhitespacesCount(currentNode.text);
+
+        if (currentNodeWhitespace > getLeadingWhitespacesCount(previousNode.text)) {
+          currentNode.parentNode = previousNode;
+          previousNode.contents.pushObject(currentNode);
+        } else {
+          for (var j = i - 1; j >= 0; j--) {
+            if (currentNodeWhitespace === getLeadingWhitespacesCount(explainSet[j].text)) {
+              if (currentNodeWhitespace > 0) {
+                currentNode.parentNode = explainSet[j].parentNode;
+                currentNode.parentNode.contents.pushObject(currentNode);
+              } else {
+                formatted.pushObject(currentNode);
+              }
+
+              break;
+            }
+          }
+        }
+      } else {
+        formatted.pushObject(currentNode);
+      }
+    }
+
+    this.set('formattedExplain', formatted);
+  }
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js
new file mode 100644
index 0000000..43c7a7e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js
@@ -0,0 +1,108 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+import utils from 'hive/utils/functions';
+
+export default Ember.ObjectController.extend({
+  fileService: Ember.inject.service(constants.namingConventions.file),
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+
+  needs: [ constants.namingConventions.queryTabs,
+           constants.namingConventions.index,
+           constants.namingConventions.openQueries ],
+
+  queryTabs: Ember.computed.alias('controllers.' + constants.namingConventions.queryTabs),
+  index: Ember.computed.alias('controllers.' + constants.namingConventions.index),
+  openQueries: Ember.computed.alias('controllers.' + constants.namingConventions.openQueries),
+
+  reloadJobLogs: function (job) {
+    var self = this;
+    var handleError = function (error) {
+      job.set('isRunning', false);
+
+      self.get('notifyService').error(error);
+    };
+
+    job.reload().then(function () {
+      if (utils.insensitiveCompare(job.get('status'), constants.statuses.error) ||
+          utils.insensitiveCompare(job.get('status'), constants.statuses.failed)) {
+        handleError(job.get('statusMessage'));
+      }
+
+      self.get('fileService').reloadFile(job.get('logFile')).then(function (file) {
+        var fileContent = file.get('fileContent');
+        var stillRunning = self.isJobRunning(job);
+        var currentIndexModelId = self.get('index.model.id');
+        var currentActiveTab = self.get('queryTabs.activeTab.name');
+
+        if (fileContent) {
+          job.set('log', fileContent);
+        }
+
+        //if the current model is the same with the one displayed, continue reloading job
+        if (stillRunning) {
+          Ember.run.later(self, function () {
+            this.reloadJobLogs(job);
+          }, 10000);
+        } else if (!stillRunning) {
+          job.set('isRunning', undefined);
+          job.set('retrievingLogs', false);
+
+          if (utils.insensitiveCompare(job.get('status'), constants.statuses.succeeded)) {
+            self.get('openQueries').updateTabSubroute(job, constants.namingConventions.subroutes.jobResults);
+
+            if (job.get('id') === currentIndexModelId && currentActiveTab === constants.namingConventions.index) {
+              self.transitionToRoute(constants.namingConventions.subroutes.historyQuery, job.get('id'));
+            }
+          }
+        }
+
+      },function (err) {
+        handleError(err);
+      });
+    }, function (err) {
+      handleError(err);
+    });
+  },
+
+  isJobRunning: function (job) {
+    return utils.insensitiveCompare(job.get('status'),
+                                    constants.statuses.unknown,
+                                    constants.statuses.initialized,
+                                    constants.statuses.running,
+                                    constants.statuses.pending);
+  },
+
+  getLogs: function () {
+    var job = this.get('content');
+
+    if (this.isJobRunning(job)) {
+      if (!job.get('retrievingLogs')) {
+        job.set('retrievingLogs', true);
+        job.set('isRunning', true);
+        this.reloadJobLogs(job);
+      }
+    } else if (utils.insensitiveCompare(job.get('status'), constants.statuses.succeeded) && !job.get('dagId')) {
+      //if a job that never polled for logs is succeeded, jump straight to results tab.
+      this.get('openQueries').updateTabSubroute(job, constants.namingConventions.subroutes.jobResults);
+      this.transitionToRoute(constants.namingConventions.subroutes.historyQuery, job.get('id'));
+    }
+  }.observes('content')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.js
new file mode 100644
index 0000000..9e94b17
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/results.js
@@ -0,0 +1,238 @@
+
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+import utils from 'hive/utils/functions';
+
+export default Ember.ObjectController.extend({
+  cachedResults: [],
+  formattedResults: [],
+
+  processResults: function () {
+    var results = this.get('results');
+    var filterValue = this.get('filterValue');
+    var columns;
+    var rows;
+    var filteredColumns;
+    var filteredRows;
+
+    if (!results) {
+      return;
+    }
+
+    columns = results.schema;
+    rows = results.rows;
+
+    if (!columns || !rows) {
+      return;
+    }
+
+    columns = columns.map(function (column) {
+      return {
+        name: column[0],
+        type: column[1],
+        index: column[2] - 1 //normalize index to 0 based
+      };
+    });
+
+    if (filterValue) {
+      filteredColumns = columns.filter(function (column) {
+        return utils.insensitiveContains(column.name, filterValue);
+      });
+
+      if (filteredColumns.length < columns.length) {
+        filteredRows = rows.map(function (row) {
+          var updatedRow = [];
+
+          updatedRow.pushObjects(row.filter(function (item, index) {
+            return this.findBy('index', index);
+          }, this));
+
+          return updatedRow;
+        }, filteredColumns);
+      } else {
+        filteredRows = rows;
+      }
+    } else {
+      filteredColumns = columns;
+      filteredRows = rows;
+    }
+
+    this.set('formattedResults', { columns: filteredColumns, rows: filteredRows });
+  }.observes('results', 'filterValue'),
+
+  keepAlive: function (job) {
+    Ember.run.later(this, function () {
+      var self = this;
+      var url = this.container.lookup('adapter:application').buildURL();
+      url += '/' + constants.namingConventions.jobs + '/' + job.get('id') + '/results/keepAlive';
+
+      var existingJob = self.cachedResults.findBy('id', job.get('id'));
+
+      if (existingJob) {
+        Ember.$.getJSON(url).fail(function (data) {
+          //backend issue, this will be split in done and fail callbacks once its fixed.
+          if (data.status === 404) {
+            existingJob.set('results', []);
+            self.set('error', data.responseJSON.message);
+          } else if (data.status === 200) {
+            self.keepAlive(job);
+          }
+        });
+      }
+    }, 1000 * 300);
+  },
+
+  clearCachedResultsSet: function (jobId) {
+    this.set('cachedResults', this.get('cachedResults').without(this.get('cachedResults').findBy('id', jobId)));
+  },
+
+  initResults: function () {
+    var existingJob;
+
+    if (!utils.insensitiveCompare(this.get('content.status'), constants.statuses.succeeded)) {
+      return;
+    }
+
+    existingJob = this.cachedResults.findBy('id', this.get('content.id'));
+
+    if (existingJob) {
+      this.set('results', existingJob.results.findBy('offset', existingJob.get('offset')));
+    } else {
+      this.send('getNextPage', true);
+    }
+  }.observes('content.status'),
+
+  disableNext: function () {
+    return !this.get('results.hasNext');
+  }.property('results'),
+
+  disablePrevious: function () {
+    return this.cachedResults.findBy('id', this.get('content.id')).results.indexOf(this.get('results')) <= 0;
+  }.property('results'),
+
+  getResultsJson: function (job) {
+    var defer = Ember.RSVP.defer();
+    var url = this.container.lookup('adapter:application').buildURL();
+    url += '/' + constants.namingConventions.jobs + '/' + job.get('id') + '/results?first=true';
+
+    Ember.$.getJSON(url).then(function (results) {
+      defer.resolve(JSON.parse(results.rows[0][0]));
+    }, function (err) {
+      defer.reject(err);
+    });
+
+    return defer.promise;
+  },
+
+  getResult : function(url){
+    var promise = new Ember.RSVP.Promise(function(resolve,reject){
+      var getData =  function(){
+        //console.log("getData called.");
+        Ember.$.getJSON(url).done(function(data){
+          console.log('results.js : getResult : got success data');
+          resolve(data);
+        }).fail(function(err){
+          if(err.status == 503 && err.getResponseHeader('Retry-After')){
+            var time = Number(err.getResponseHeader('Retry-After'));
+            console.log("results.js : getResult : got error : " + err.status + " with retry.");
+            Ember.run.later(this,
+            function(){
+              getData();
+            },time*1000);
+          }else{
+            console.log("results.js : getResult : rejected. ");
+            reject(err);
+          }
+        });
+      };
+      getData();
+    });
+
+    return promise;
+  },
+
+  actions: {
+    getNextPage: function (firstPage, job) {
+      var self = this;
+      var id = job ? job.get('id') : this.get('content.id');
+      var existingJob = this.cachedResults.findBy('id', id);
+      var resultsIndex;
+      var url = this.container.lookup('adapter:application').buildURL();
+      url += '/' + constants.namingConventions.jobs + '/' + id + '/results';
+
+      if (firstPage) {
+        url += '?first=true';
+      }
+
+      if (existingJob) {
+        resultsIndex = existingJob.results.indexOf(this.get('results'));
+
+        if (~resultsIndex && resultsIndex < existingJob.get('results.length') - 1) {
+          this.set('results', existingJob.results.objectAt(resultsIndex + 1));
+          return;
+        }
+      }
+
+      this.getResult(url)
+      .then(function (results) {
+        //console.log("inside then : ", results);
+        if (existingJob) {
+          existingJob.results.pushObject(results);
+          existingJob.set('offset', results.offset);
+        } else {
+          self.cachedResults.pushObject(Ember.Object.create({
+            id: id,
+            results: [ results ],
+            offset: results.offset
+          }));
+        }
+
+        //only set results if the method was called for the current model, not after a keepAlive request.
+        if (!job) {
+          self.set('results', results);
+        }
+
+        if (firstPage) {
+          self.keepAlive(job || self.get('content'));
+        }
+
+      }, function (err) {
+        self.set('error', err.responseText);
+      });
+    },
+
+    getPreviousPage: function () {
+      var existingJob,
+          resultsIndex;
+
+      existingJob = this.cachedResults.findBy('id', this.get('content.id'));
+      resultsIndex = existingJob.results.indexOf(this.get('results'));
+
+      if (resultsIndex > 0) {
+        this.set('results', existingJob.results.objectAt(resultsIndex - 1));
+      }
+    },
+
+    filterResults: function (value) {
+      this.set('filterValue', value);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/insert-udfs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/insert-udfs.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/insert-udfs.js
new file mode 100644
index 0000000..09f17c3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/insert-udfs.js
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.ArrayController.extend({
+  needs: [ constants.namingConventions.udfs ],
+
+  model: Ember.A(),
+
+  udfs: Ember.computed.alias('controllers.' + constants.namingConventions.udfs + '.udfs'),
+
+  updateUdfs: function () {
+    var self = this,
+        udfs = this.get('udfs'),
+        udfsWithoutFiles;
+
+    this.clear();
+
+    if (udfs && udfs.get('length')) {
+      udfs.getEach('fileResource.id').uniq().forEach(function (fileResourceId) {
+        if (fileResourceId) {
+          self.pushObject(Ember.Object.create({
+            file: udfs.findBy('fileResource.id', fileResourceId).get('fileResource'),
+            udfs: udfs.filterBy('fileResource.id', fileResourceId)
+          }));
+        }
+      });
+
+      udfsWithoutFiles = udfs.filter(function (udf) {
+        return !udf.get('isNew') && !udf.get('fileResource.id');
+      });
+
+      if (udfsWithoutFiles.get('length')) {
+       self.pushObject(Ember.Object.create({
+          name: "placeholders.select.noFileResource",
+          udfs: udfsWithoutFiles
+        }));
+      }
+    }
+  }.on('init').observes('udfs.@each.isNew')
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/messages.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/messages.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/messages.js
new file mode 100644
index 0000000..11295d8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/messages.js
@@ -0,0 +1,41 @@
+/**
+* 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.
+*/
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+
+  messages: Ember.computed.alias('notifyService.messages'),
+  count: Ember.computed.alias('notifyService.unseenMessages.length'),
+
+  actions: {
+    removeMessage: function (message) {
+      this.get('notifyService').removeMessage(message);
+    },
+
+    removeAllMessages: function () {
+      this.get('notifyService').removeAllMessages();
+    },
+
+    markMessagesAsSeen: function () {
+      this.get('notifyService').markMessagesAsSeen();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/modal-delete.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/modal-delete.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/modal-delete.js
new file mode 100644
index 0000000..0fbcd6b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/modal-delete.js
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+  actions: {
+     delete: function () {
+      this.send('closeModal');
+      this.defer.resolve();
+    },
+
+    close: function () {
+      this.send('closeModal');
+      this.defer.reject();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/modal-save-query.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/modal-save-query.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/modal-save-query.js
new file mode 100644
index 0000000..d878bc7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/modal-save-query.js
@@ -0,0 +1,42 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import ModalSave from '../controllers/modal-save';
+import constants from '../utils/constants';
+
+export default ModalSave.extend({
+  showMessage: function () {
+    var content = this.get('content');
+
+    return !content.get('isNew') &&
+            content.get('title') === this.get('text') &&
+            content.get('constructor.typeKey') !== constants.namingConventions.job;
+  }.property('content.isNew', 'text'),
+
+  actions: {
+    save: function () {
+      this.send('closeModal');
+
+      this.defer.resolve(Ember.Object.create({
+        text: this.get('text'),
+        overwrite: this.get('showMessage')
+      }));
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/modal-save.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/modal-save.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/modal-save.js
new file mode 100644
index 0000000..6c16291
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/modal-save.js
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+  actions: {
+    save: function () {
+      this.send('closeModal');
+      this.defer.resolve(this.get('text'));
+      this.defer.resolve(this.get('type'));
+    },
+
+    close: function () {
+      this.send('closeModal');
+      this.defer.reject();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/open-queries.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/open-queries.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/open-queries.js
new file mode 100644
index 0000000..a4048be
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/open-queries.js
@@ -0,0 +1,397 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+import utils from 'hive/utils/functions';
+
+export default Ember.ArrayController.extend({
+  fileService: Ember.inject.service(constants.namingConventions.file),
+  databaseService: Ember.inject.service(constants.namingConventions.database),
+
+  needs: [ constants.namingConventions.jobResults,
+           constants.namingConventions.jobExplain,
+           constants.namingConventions.index
+         ],
+
+  jobResults: Ember.computed.alias('controllers.' + constants.namingConventions.jobResults),
+  jobExplain: Ember.computed.alias('controllers.' + constants.namingConventions.jobExplain),
+  index: Ember.computed.alias('controllers.' + constants.namingConventions.index),
+
+  selectedTables: Ember.computed.alias('databaseService.selectedTables'),
+  selectedDatabase: Ember.computed.alias('databaseService.selectedDatabase'),
+
+  init: function () {
+    this._super();
+
+    this.set('queryTabs', Ember.ArrayProxy.create({ content: Ember.A([])}));
+  },
+
+  pushObject: function (queryFile, model) {
+    return this._super(queryFile || Ember.Object.create({
+      id: model.get('id'),
+      fileContent: ""
+    }));
+  },
+
+  getTabForModel: function (model) {
+    return this.get('queryTabs').find(function (tab) {
+      return tab.id === model.get('id') && tab.type === model.get('constructor.typeKey');
+    });
+  },
+
+  updateTabSubroute: function (model, path) {
+    var tab = this.get('queryTabs').find(function (tab) {
+      return tab.id === model.get('id') && tab.type === model.get('constructor.typeKey');
+    });
+
+    if (tab) {
+      tab.set('subroute', path);
+    }
+  },
+
+  getQueryForModel: function (model) {
+    return this.find(function (openQuery) {
+      if (model.get('isNew')) {
+        return openQuery.get('id') === model.get('id');
+      }
+
+      return openQuery.get('id') === model.get('queryFile');
+    });
+  },
+
+  update: function (model) {
+    var path,
+        type,
+        currentQuery,
+        defer = Ember.RSVP.defer(),
+        existentTab,
+        self = this,
+        updateSubroute = function () {
+          var isExplainedQuery,
+              subroute;
+
+          //jobs that were run from hive ui (exclude ats jobs)
+          if (model.get('constructor.typeKey') === constants.namingConventions.job &&
+              utils.isInteger(model.get('id'))) {
+            isExplainedQuery = self.get('currentQuery.fileContent').indexOf(constants.namingConventions.explainPrefix) > -1;
+
+            if (isExplainedQuery) {
+              subroute = constants.namingConventions.subroutes.jobExplain;
+            } else {
+              subroute = constants.namingConventions.subroutes.jobLogs;
+            }
+
+            if (!existentTab.get('subroute')) {
+              self.updateTabSubroute(model, subroute);
+            }
+          }
+
+          defer.resolve(isExplainedQuery);
+        };
+
+    existentTab = this.getTabForModel(model);
+
+    if (!existentTab) {
+      type = model.get('constructor.typeKey');
+      path = type === constants.namingConventions.job ?
+             constants.namingConventions.subroutes.historyQuery :
+             constants.namingConventions.subroutes.savedQuery;
+
+      existentTab = this.get('queryTabs').pushObject(Ember.Object.create({
+        name: model.get('title'),
+        id: model.get('id'),
+        visible: true,
+        path: path,
+        type: type
+      }));
+
+      if (model.get('isNew')) {
+        this.set('currentQuery', this.pushObject(null, model));
+
+        defer.resolve();
+      } else {
+        this.get('fileService').loadFile(model.get('queryFile')).then(function (file) {
+          self.set('currentQuery', self.pushObject(file));
+
+          updateSubroute();
+        });
+
+        if (model.get('logFile') && !model.get('log')) {
+          this.get('fileService').loadFile(model.get('logFile')).then(function (file) {
+            model.set('log', file.get('fileContent'));
+          });
+        }
+      }
+    } else {
+      currentQuery = this.getQueryForModel(model);
+      this.set('currentQuery', currentQuery);
+
+      updateSubroute();
+    }
+
+    return defer.promise;
+  },
+
+  save: function (model, query, isUpdating, newTitle) {
+    var tab = this.getTabForModel(model),
+        self = this,
+        wasNew,
+        defer = Ember.RSVP.defer(),
+        jobModel = model;
+
+    if (!query) {
+      query = this.getQueryForModel(model);
+    }
+
+    if (model.get('isNew')) {
+      wasNew = true;
+      model.set('title', newTitle);
+      model.set('id', null);
+    }
+
+    //if current query it's a job, convert it to a savedQuery before saving
+    if (model.get('constructor.typeKey') === constants.namingConventions.job) {
+      model = this.store.createRecord(constants.namingConventions.savedQuery, {
+        dataBase: this.get('selectedDatabase.name'),
+        title: newTitle,
+        queryFile: model.get('queryFile'),
+        owner: model.get('owner')
+      });
+    }
+
+    tab.set('name', newTitle);
+
+    //if saving a new query from an existing one create a new record and save it
+    if (!isUpdating && !model.get('isNew') && model.get('constructor.typeKey') !== constants.namingConventions.job) {
+      model = this.store.createRecord(constants.namingConventions.savedQuery, {
+        dataBase: this.get('selectedDatabase.name'),
+        title: newTitle,
+        owner: model.get('owner')
+      });
+
+      wasNew = true;
+    }
+
+    model.save().then(function (updatedModel) {
+      jobModel.set('queryId', updatedModel.get('id'));
+
+      tab.set('isDirty', false);
+
+      var content = query.get('fileContent');
+      content = self.get('index').buildQuery(query);
+      content = self.get('index').bindQueryParams(content);
+
+      //update query tab path with saved model id if its a new record
+      if (wasNew) {
+        tab.set('id', updatedModel.get('id'));
+
+        self.get('fileService').loadFile(updatedModel.get('queryFile')).then(function (file) {
+          file.set('fileContent', content);
+          file.save().then(function (updatedFile) {
+            self.removeObject(query);
+            self.pushObject(updatedFile);
+            self.set('currentQuery', updatedFile);
+
+            defer.resolve(updatedModel.get('id'));
+          }, function (err) {
+            defer.reject(err);
+          });
+        }, function (err) {
+          defer.reject(err);
+        });
+      } else {
+        query.set('fileContent', content);
+        query.save().then(function () {
+          self.toggleProperty('tabUpdated');
+          defer.resolve(updatedModel.get('id'));
+
+        }, function (err) {
+          defer.reject(err);
+        });
+      }
+    }, function (err) {
+      defer.reject(err);
+    });
+
+    return defer.promise;
+  },
+
+  convertTabToJob: function (model, job) {
+    var defer = Ember.RSVP.defer(),
+        oldQuery = this.getQueryForModel(model),
+        tab = this.getTabForModel(model),
+        jobId = job.get('id'),
+        self = this;
+
+    tab.set('id', job.get('id'));
+    tab.set('type', constants.namingConventions.job);
+    tab.set('path', constants.namingConventions.subroutes.historyQuery);
+
+    this.get('fileService').loadFile(job.get('queryFile')).then(function (file) {
+      //replace old model representing file to reflect model update to job
+      if (self.keepOriginalQuery(jobId)) {
+        file.set('fileContent', oldQuery.get('fileContent'));
+      }
+
+      // Rollback the oldQuery if it is a DS model (type: 'savedQuery)
+      if (oldQuery.get('constructor.typeKey') !== undefined) {
+        oldQuery.rollback();
+      }
+
+      self.removeObject(oldQuery);
+      self.pushObject(file);
+
+      defer.resolve();
+    }, function (err) {
+      defer.reject(err);
+    });
+
+    return defer.promise;
+  },
+
+  keepOriginalQuery: function () {
+    var selected = this.get('highlightedText');
+    var hasQueryParams = this.get('index.queryParams.length');
+
+    return selected && selected[0] !== "" || hasQueryParams;
+  },
+
+  isDirty: function (model) {
+    var query = this.getQueryForModel(model);
+
+    if (model.get('isNew') && !query.get('fileContent')) {
+      return false;
+    }
+
+    if (query && query.get('isDirty')) {
+      return true;
+    }
+
+    return !!(!model.get('queryId') && model.get('isDirty'));
+  },
+
+  updatedDeletedQueryTab: function (model) {
+    var tab = this.getTabForModel(model);
+
+    if (tab) {
+      this.closeTab(tab);
+    }
+  },
+
+  dirtyObserver: function () {
+    var tab;
+    var model = this.get('index.model');
+
+    if (model) {
+      tab = this.getTabForModel(model);
+
+      if (tab) {
+        tab.set('isDirty', this.isDirty(model));
+      }
+    }
+  }.observes('currentQuery.isDirty', 'currentQuery.fileContent'),
+
+  closeTab: function (tab, goToNextTab) {
+    var remainingTabs = this.get('queryTabs').without(tab);
+
+    this.set('queryTabs', remainingTabs);
+
+    //remove cached results set
+    if (tab.type === constants.namingConventions.job) {
+      this.get('jobResults').clearCachedResultsSet(tab.id);
+      this.get('jobExplain').clearCachedExplainSet(tab.id);
+    }
+
+    if (goToNextTab) {
+      this.navigateToLastTab();
+    }
+  },
+
+  navigateToLastTab: function () {
+    var lastTab = this.get('queryTabs.lastObject');
+
+    if (lastTab) {
+      if (lastTab.type === constants.namingConventions.job) {
+        this.transitionToRoute(constants.namingConventions.subroutes.historyQuery, lastTab.id);
+      } else {
+        this.transitionToRoute(constants.namingConventions.subroutes.savedQuery, lastTab.id);
+      }
+    } else {
+      this.get('index').send('addQuery');
+    }
+  },
+
+  actions: {
+    removeQueryTab: function (tab) {
+      var self = this,
+          defer;
+
+      this.store.find(tab.type, tab.id).then(function (model) {
+        var query = self.getQueryForModel(model);
+
+        if (!self.isDirty(model)) {
+          self.closeTab(tab, true);
+        } else {
+          defer = Ember.RSVP.defer();
+          self.send('openModal',
+                    'modal-save',
+                     {
+                        heading: "modals.save.saveBeforeCloseHeading",
+                        text: model.get('title'),
+                        defer: defer
+                     });
+
+          defer.promise.then(function (text) {
+            model.set('title', text);
+            self.save(model, query, false, text).then(function () {
+              self.closeTab(tab, true);
+            });
+          }, function () {
+            model.rollback();
+            query.rollback();
+            self.closeTab(tab, true);
+          });
+        }
+      });
+    },
+
+    getColumnsForAutocomplete: function (tableName, callback) {
+      this.get('databaseService').getAllColumns(tableName).then(function () {
+        callback();
+      });
+    },
+
+    changeTabTitle: function(tab) {
+      var self = this,
+          defer = Ember.RSVP.defer(),
+          title = this.get('index.content.title');
+
+      this.send('openModal', 'modal-save', {
+        heading: 'modals.changeTitle.heading',
+        text: title,
+        defer: defer
+      });
+
+      defer.promise.then(function (result) {
+        self.set('index.model.title', result);
+        tab.set('name', result);
+      });
+    }
+  }
+});


[23/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/service.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service.js b/ambari-web/app/controllers/main/service.js
index 44b8b21..e64518b 100644
--- a/ambari-web/app/controllers/main/service.js
+++ b/ambari-web/app/controllers/main/service.js
@@ -17,7 +17,6 @@
  */
 
 var App = require('app');
-var misc = require('utils/misc');
 
 App.MainServiceController = Em.ArrayController.extend({
 
@@ -30,9 +29,14 @@ App.MainServiceController = Em.ArrayController.extend({
     if (!App.router.get('clusterController.isLoaded')) {
       return [];
     }
-    return misc.sortByOrder(App.StackService.find().mapProperty('serviceName'), App.Service.find().toArray());
+    return App.ServiceGroup.find();
   }.property('App.router.clusterController.isLoaded').volatile(),
 
+  isAllCoreServicesInstalled: function() {
+    var coreServiceGroup = this.get('content').findProperty('serviceGroupName', 'CORE');
+    return coreServiceGroup ? this.get('content').findProperty('id', 'CORE').get('isAllServicesInstalled') : false;
+  }.property('content.@each.isAllServicesInstalled'),
+
   /**
    * Current cluster
    * @type {Ember.Object}
@@ -45,59 +49,15 @@ App.MainServiceController = Em.ArrayController.extend({
   }.property('App.router.clusterController.isClusterDataLoaded'),
 
   /**
-   * Check if all services are installed
-   * true - all installed, false - not all
-   * @type {bool}
-   */
-  isAllServicesInstalled: function () {
-    if (!this.get('content')) return false;
-    var availableServices = App.StackService.find().mapProperty('serviceName');
-    return this.get('content').length == availableServices.length;
-  }.property('content.@each', 'content.length'),
-
-  /**
-   * Should "Start All"-button be disabled
-   * @type {bool}
-   */
-  isStartAllDisabled: function () {
-    if (this.get('isStartStopAllClicked') == true) {
-      return true;
-    }
-    var stoppedServices = this.get('content').filter(function (_service) {
-      return (_service.get('healthStatus') === 'red' && !App.get('services.clientOnly').contains(_service.get('serviceName')));
-    });
-    return (stoppedServices.length === 0); // all green status
-  }.property('isStartStopAllClicked', 'content.@each.healthStatus'),
-
-  /**
-   * Should "Stop All"-button be disabled
-   * @type {bool}
-   */
-  isStopAllDisabled: function () {
-    if (this.get('isStartStopAllClicked') == true) {
-      return true;
-    }
-    return !this.get('content').someProperty('healthStatus', 'green');
-  }.property('isStartStopAllClicked', 'content.@each.healthStatus'),
-
-  /**
-   * Should "Refresh All"-button be disabled
-   * @type {bool}
-   */
-  isRestartAllRequiredDisabled: Em.computed.everyBy('content', 'isRestartRequired', false),
-
-  /**
-   * @type {bool}
-   */
-  isStartStopAllClicked: Em.computed.notEqual('App.router.backgroundOperationsController.allOperationsCount', 0),
-
-  /**
    * Callback for <code>start all service</code> button
    * @return {App.ModalPopup|null}
    * @method startAllService
    */
   startAllService: function (event) {
-    return this.startStopAllService(event, 'STARTED');
+    var serviceGroup = event.context;
+    if (!serviceGroup || !serviceGroup.get('isStartAllDisabled')) {
+      return this.startStopAllService(serviceGroup, 'STARTED');
+    }
   },
 
   /**
@@ -106,59 +66,81 @@ App.MainServiceController = Em.ArrayController.extend({
    * @method stopAllService
    */
   stopAllService: function (event) {
-    return this.startStopAllService(event, 'INSTALLED');
+    var serviceGroup = event.context;
+    if (!serviceGroup || !serviceGroup.get('isStopAllDisabled')) {
+      return this.startStopAllService(serviceGroup, 'INSTALLED');
+    }
   },
 
   /**
    * Common method for "start-all", "stop-all" calls
-   * @param {object} event
+   * @param {object} serviceGroup
    * @param {string} state 'STARTED|INSTALLED'
    * @returns {App.ModalPopup|null}
    * @method startStopAllService
    */
-  startStopAllService: function(event, state) {
-    if ($(event.target).hasClass('disabled') || $(event.target.parentElement).hasClass('disabled')) {
-      return null;
-    }
+  startStopAllService: function(serviceGroup, state) {
     var self = this;
+    var _serviceGroup = serviceGroup || Em.Object.create();
+    var serviceGroupName = _serviceGroup.get('serviceGroupName');
+    var isCoreServiceGroup = serviceGroupName === 'CORE';
+    var confirmStopMsg, confirmStartMsg;
+    if (serviceGroupName === 'CORE') {
+      confirmStopMsg = Em.I18n.t('services.service.core.stopAll.confirmMsg');
+      confirmStartMsg = Em.I18n.t('services.service.core.startAll.confirmMsg');
+    } else {
+      if(serviceGroupName) {
+        confirmStopMsg = Em.I18n.t('services.service.stopAll.confirmMsg');
+        confirmStartMsg = Em.I18n.t('services.service.startAll.confirmMsg');
+      }
+      else {
+        confirmStopMsg = Em.I18n.t('services.service.cluster.stopAll.confirmMsg');
+        confirmStartMsg = Em.I18n.t('services.service.cluster.startAll.confirmMsg');
+      }
+    }
     var bodyMessage = Em.Object.create({
-      confirmMsg: state == 'INSTALLED' ? Em.I18n.t('services.service.stopAll.confirmMsg') : Em.I18n.t('services.service.startAll.confirmMsg'),
-      confirmButton: state == 'INSTALLED' ? Em.I18n.t('services.service.stop.confirmButton') : Em.I18n.t('services.service.start.confirmButton')
+      confirmMsg: state === 'INSTALLED' ? confirmStopMsg.format(serviceGroupName) : confirmStartMsg.format(serviceGroupName),
+      confirmButton: state === 'INSTALLED' ? Em.I18n.t('services.service.stop.confirmButton') : Em.I18n.t('services.service.start.confirmButton')
     });
 
-    if (state == 'INSTALLED' && App.Service.find().filterProperty('serviceName', 'HDFS').someProperty('workStatus', App.HostComponentStatus.started)) {
-      App.router.get('mainServiceItemController').checkNnLastCheckpointTime(function () {
+    if (isCoreServiceGroup && state === 'INSTALLED' && App.Service.find().filterProperty('serviceName', 'HDFS').someProperty('workStatus', App.HostComponentStatus.started)) {
+      return App.router.get('mainServiceItemController').checkNnLastCheckpointTime(function () {
         return App.showConfirmationFeedBackPopup(function (query) {
-          self.allServicesCall(state, query);
+          self.allServicesCall(state, query, _serviceGroup);
         }, bodyMessage);
       });
-    } else {
-      return App.showConfirmationFeedBackPopup(function (query) {
-        self.allServicesCall(state, query);
-      }, bodyMessage);
     }
+    return App.showConfirmationFeedBackPopup(function (query) {
+      self.allServicesCall(state, query, _serviceGroup);
+    }, bodyMessage);
   },
 
   /**
    * Do request to server for "start|stop" all services
    * @param {string} state "STARTED|INSTALLED"
    * @param {object} query
+   * @param {object} serviceGroup
    * @method allServicesCall
    * @return {$.ajax}
    */
-  allServicesCall: function (state, query) {
-    var context = (state == 'INSTALLED') ? App.BackgroundOperationsController.CommandContexts.STOP_ALL_SERVICES :
+  allServicesCall: function (state, query, serviceGroup) {
+    var context = state === 'INSTALLED' ? App.BackgroundOperationsController.CommandContexts.STOP_ALL_SERVICES :
       App.BackgroundOperationsController.CommandContexts.START_ALL_SERVICES;
+    var services = serviceGroup.get('services') || App.Service.find();
+    var servicesList = services.mapProperty("serviceName").join(',');
+    var data = {
+      context: context,
+        ServiceInfo: {
+        state: state
+      },
+      urlParams: "ServiceInfo/service_name.in(" + servicesList + ")",
+      query: query
+    };
+
     return App.ajax.send({
       name: 'common.services.update',
       sender: this,
-      data: {
-        context: context,
-        ServiceInfo: {
-          state: state
-        },
-        query: query
-      },
+      data: data,
       success: 'allServicesCallSuccessCallback',
       error: 'allServicesCallErrorCallback'
     });
@@ -288,7 +270,7 @@ App.MainServiceController = Em.ArrayController.extend({
    * @method gotoAddService
    */
   gotoAddService: function () {
-    if (this.get('isAllServicesInstalled')) {
+    if (this.get('isAllCoreServicesInstalled')) {
       return;
     }
     App.router.get('addServiceController').setDBProperty('onClosePath', 'main.services.index');
@@ -298,9 +280,9 @@ App.MainServiceController = Em.ArrayController.extend({
   /**
    * Show confirmation popup and send request to restart all host components with stale_configs=true
    */
-  restartAllRequired: function () {
+  restartAllRequired: function (serviceGroup) {
     var self = this;
-    if (!this.get('isRestartAllRequiredDisabled')) {
+    if (!serviceGroup.get('isRestartAllRequiredDisabled')) {
       return App.showConfirmationPopup(function () {
             self.restartHostComponents();
           }, Em.I18n.t('services.service.refreshAll.confirmMsg').format(

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/service/info/configs.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/info/configs.js b/ambari-web/app/controllers/main/service/info/configs.js
index b6e6c21..57c013e 100644
--- a/ambari-web/app/controllers/main/service/info/configs.js
+++ b/ambari-web/app/controllers/main/service/info/configs.js
@@ -97,8 +97,8 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader, A
    * @type {string[]}
    */
   servicesToLoad: function() {
-    return [this.get('content.serviceName')].concat(this.get('dependentServiceNames')).uniq();
-  }.property('content.serviceName', 'dependentServiceNames.length'),
+    return [this.get('content.stackServiceName')].concat(this.get('dependentServiceNames')).uniq();
+  }.property('content.stackServiceName', 'dependentServiceNames.length'),
 
   /**
    * @type {boolean}
@@ -291,7 +291,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader, A
    * @method loadStep
    */
   loadStep: function () {
-    var serviceName = this.get('content.serviceName');
+    var serviceName = this.get('content.stackServiceName');
     this.clearStep();
     this.set('dependentServiceNames', App.StackService.find(serviceName).get('dependentServiceNames'));
     this.loadConfigTheme(serviceName).always(this.loadCurrentVersions.bind(this));

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/service/info/summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/info/summary.js b/ambari-web/app/controllers/main/service/info/summary.js
index eb0e850..0f29b41 100644
--- a/ambari-web/app/controllers/main/service/info/summary.js
+++ b/ambari-web/app/controllers/main/service/info/summary.js
@@ -803,7 +803,7 @@ App.MainServiceInfoSummaryController = Em.Controller.extend(App.WidgetSectionMix
           var view = this;
           var services = App.Service.find().filter(function(item){
             var stackService =  App.StackService.find().findProperty('serviceName', item.get('serviceName'));
-            return stackService.get('isServiceWithWidgets');
+            return stackService.get('isServiceWithWidgets') && item.get('serviceGroupName') === 'CORE';
           });
           return services.map(function (service) {
             return Em.Object.create({

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js b/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js
index e833ead..677bc05 100644
--- a/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js
+++ b/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js
@@ -210,7 +210,7 @@ App.WidgetWizardController = App.WizardController.extend({
       data: {
         stackVersionURL: App.get('stackVersionURL'),
         serviceNames: App.Service.find().filter(function (item) {
-          return App.StackService.find(item.get('id')).get('isServiceWithWidgets');
+          return App.StackService.find(item.get('id')).get('isServiceWithWidgets') && item.get('serviceGroupName') === 'CORE';
         }).mapProperty('serviceName').join(',')
       },
       callback: callback,

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/mappers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers.js b/ambari-web/app/mappers.js
index 96193bc..5937536 100644
--- a/ambari-web/app/mappers.js
+++ b/ambari-web/app/mappers.js
@@ -32,6 +32,7 @@ require('mappers/cluster_mapper');
 require('mappers/racks_mapper');
 require('mappers/users_mapper');
 require('mappers/service_mapper');
+require('mappers/service_group_mapper');
 require('mappers/service_metrics_mapper');
 require('mappers/target_cluster_mapper');
 require('mappers/component_config_mapper');

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/mappers/components_state_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/components_state_mapper.js b/ambari-web/app/mappers/components_state_mapper.js
index eb9ebd5..0c2d45c 100644
--- a/ambari-web/app/mappers/components_state_mapper.js
+++ b/ambari-web/app/mappers/components_state_mapper.js
@@ -24,7 +24,7 @@ App.componentsStateMapper = App.QuickDataMapper.create({
 
   clientModel: App.ClientComponent,
   clientMap: {
-    id: 'ServiceComponentInfo.component_name',
+    id: 'ServiceComponentInfo.id',
     service_id: 'ServiceComponentInfo.service_name',
     stack_info_id: 'ServiceComponentInfo.component_name',
     component_name: 'ServiceComponentInfo.component_name',
@@ -167,6 +167,7 @@ App.componentsStateMapper = App.QuickDataMapper.create({
 
     if (json.items) {
       json.items.forEach(function (item) {
+        item.ServiceComponentInfo.id =  item.ServiceComponentInfo.service_name + '_' + item.ServiceComponentInfo.component_name;
         var componentConfig = this.getComponentConfig(item.ServiceComponentInfo.component_name);
         var parsedItem = this.parseIt(item, componentConfig);
         var service = App.Service.find(item.ServiceComponentInfo.service_name);
@@ -185,9 +186,15 @@ App.componentsStateMapper = App.QuickDataMapper.create({
           masters.push(this.parseIt(item, this.clientMap));
         }
         if (cacheService) {
-          cacheService.client_components = clients.filterProperty('service_name', cacheService.ServiceInfo.service_name).mapProperty('component_name');
-          cacheService.slave_components = slaves.filterProperty('service_name', cacheService.ServiceInfo.service_name).mapProperty('component_name');
-          cacheService.master_components = masters.filterProperty('service_name', cacheService.ServiceInfo.service_name).mapProperty('component_name');
+          cacheService.client_components = clients.filterProperty('service_name', cacheService.ServiceInfo.service_name).map(function(item){
+            return cacheService.ServiceInfo.service_name + '_' + item.component_name;
+          });
+          cacheService.slave_components = slaves.filterProperty('service_name', cacheService.ServiceInfo.service_name).map(function(item){
+            return cacheService.ServiceInfo.service_name + '_' + item.component_name;
+          });
+          cacheService.master_components = masters.filterProperty('service_name', cacheService.ServiceInfo.service_name).map(function(item){
+            return cacheService.ServiceInfo.service_name + '_' + item.component_name;
+          });
           for (var i in parsedItem) {
             if (service.get('isLoaded')) {
               cacheService[i] = parsedItem[i];

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/mappers/service_group_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/service_group_mapper.js b/ambari-web/app/mappers/service_group_mapper.js
new file mode 100644
index 0000000..3591619
--- /dev/null
+++ b/ambari-web/app/mappers/service_group_mapper.js
@@ -0,0 +1,122 @@
+/**
+ * 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 = require('app');
+
+App.serviceGroupMapper = App.QuickDataMapper.create({
+  model: App.ServiceGroup,
+  config: {
+    id: 'ServiceGroupInfo.service_group_name',
+    cluster_name: 'ServiceGroupInfo.cluster_name',
+    service_group_name: 'ServiceGroupInfo.service_group_name',
+    service_group_display_name: 'ServiceGroupInfo.service_group_display_name',
+    service_group_type: 'ServiceGroupInfo.service_group_type',
+    current_state: 'ServiceGroupInfo.current_state',
+    desired_state: 'ServiceGroupInfo.desired_state',
+    assembly_file: 'ServiceGroupInfo.assembly_file',
+    application_id: 'ServiceGroupInfo.application_id',
+    quicklinks: 'ServiceGroupInfo.quicklinks',
+    lifetime: 'ServiceGroupInfo.lifetime',
+    containers_key: 'ServiceGroupInfo.containers',
+    containers_type: 'array',
+    containers: {
+      item: ''
+    },
+    services_key: 'services',
+    services_type: 'array',
+    services: {
+      item: 'id'
+    }
+  },
+
+  mapServiceGroups: function(json) {
+    this.clearStackModels();
+    App.resetDsStoreTypeMap(App.ServiceGroup);
+    this.map(json);
+  },
+
+  map: function (json) {
+    console.time("App.serviceGroupMapper execution time");
+    var self = this;
+    var displayOrderLength = App.ServiceGroup.displayOrder.length;
+    var items = json.items.map(function (item, index) {
+      var displayOrderIndex = App.ServiceGroup.displayOrder.indexOf(item.ServiceGroupInfo.service_group_display_name);
+      return $.extend(item, {
+        index: displayOrderIndex == -1 ? displayOrderLength + index : displayOrderIndex
+      });
+    }).sortProperty('index');
+
+
+
+    var item = {
+      ServiceGroupInfo: {
+        cluster_name: App.get('clusterName'),
+        containers: [],
+        service_group_name: "CORE"
+      }
+    };
+    items.unshift(item);
+    var serviceGroups = items.map(function (serviceGroup) {
+      var services = [];
+      if (serviceGroup.services) {
+        services = serviceGroup.services.map(function(service) {
+          return {id: service.ServiceInfo.service_name};
+        });
+      }
+      else {
+        //TODO remove after server API will be implemented
+        services = App.Service.find()
+          .filterProperty('serviceGroupName', serviceGroup.ServiceGroupInfo.service_group_name)
+          .map(function(service) {
+            return {
+              id: service.get('id')
+            }
+          });
+      }
+      serviceGroup.services = services;
+      return self.parseIt(serviceGroup, self.get('config'));
+    });
+    App.store.loadMany(this.get('model'), serviceGroups);
+    App.store.commit();
+
+    console.timeEnd("App.serviceGroupMapper execution time");
+  },
+
+  getJsonProperty: function (json, path) {
+    if (!path) {
+      return json;
+    }
+    return this._super(json, path);
+  },
+
+  /**
+   * Clean store from already loaded data.
+   **/
+  clearStackModels: function () {
+    var models = [App.ServiceGroup];
+    models.forEach(function (model) {
+      var records = App.get('store').findAll(model).filterProperty('id');
+      records.forEach(function (rec) {
+        Ember.run(this, function () {
+          rec.deleteRecord();
+          App.store.commit();
+        });
+      }, this);
+    }, this);
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/mappers/service_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/service_mapper.js b/ambari-web/app/mappers/service_mapper.js
index 9c21789..f5d5c6a 100644
--- a/ambari-web/app/mappers/service_mapper.js
+++ b/ambari-web/app/mappers/service_mapper.js
@@ -23,7 +23,10 @@ App.serviceMapper = App.QuickDataMapper.create({
   config: {
     id: 'ServiceInfo.service_name',
     service_name: 'ServiceInfo.service_name',
-    work_status: 'ServiceInfo.state'
+    work_status: 'ServiceInfo.state',
+    stack_service_name: 'ServiceInfo.stack_service_name',
+    service_group_name: 'ServiceInfo.service_group_name',
+    service_group_id: 'ServiceInfo.service_group_name'
   },
   initialAppLoad: false,
   passiveStateMap: {},
@@ -41,7 +44,10 @@ App.serviceMapper = App.QuickDataMapper.create({
         var serviceData = {
           ServiceInfo: {
             service_name: service.ServiceInfo.service_name,
-            state: service.ServiceInfo.state
+            state: service.ServiceInfo.state,
+            stack_service_name: service.ServiceInfo.stack_service_name,
+            service_group_name: service.ServiceInfo.service_group_name,
+            service_group_id: service.ServiceInfo.service_group_name
           },
           host_components: [],
           components: []
@@ -56,7 +62,7 @@ App.serviceMapper = App.QuickDataMapper.create({
         App.serviceMetricsMapper.mapExtendedModel(item);
         return self.parseIt(item, self.get('config'));
       });
-      parsedCacheServices = misc.sortByOrder(App.StackService.find().mapProperty('serviceName'), parsedCacheServices);
+      parsedCacheServices = misc.sortByOrder(App.StackService.find().mapProperty('serviceName'), parsedCacheServices, 'stack_service_name');
       App.store.loadMany(this.get('model'), parsedCacheServices);
       App.store.commit();
       this.set('initialAppLoad', true);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/mappers/service_metrics_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/service_metrics_mapper.js b/ambari-web/app/mappers/service_metrics_mapper.js
index d862df7..b0104dd 100644
--- a/ambari-web/app/mappers/service_metrics_mapper.js
+++ b/ambari-web/app/mappers/service_metrics_mapper.js
@@ -36,7 +36,10 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({
     installed_clients: 'installed_clients',
     client_components: 'client_components',
     slave_components: 'slave_components',
-    master_components: 'master_components'
+    master_components: 'master_components',
+    stack_service_name: 'ServiceInfo.stack_service_name',
+    service_group_name: 'ServiceInfo.service_group_name',
+    service_group_id: 'ServiceInfo.service_group_name'
   },
   hdfsConfig: {
     version: 'nameNodeComponent.host_components[0].metrics.dfs.namenode.Version',
@@ -203,6 +206,7 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({
           previousComponentPassiveStates[host_component.id] = host_component.HostRoles.maintenance_state;
           this.config3.ha_status = host_component.HostRoles.component_name == "HBASE_MASTER" ?
             'metrics.hbase.master.IsActiveMaster' : 'HostRoles.ha_state';
+          host_component.HostRoles.display_name = component.ServiceComponentInfo.display_name;
           var comp = this.parseIt(host_component, this.config3);
           comp.id = id;
           comp.service_id = serviceName;
@@ -248,7 +252,7 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({
       }, this);
 
       var stackServices = App.StackService.find().mapProperty('serviceName');
-      result = misc.sortByOrder(stackServices, result);
+      result = misc.sortByOrder(stackServices, result, 'stack_service_name');
 
       //load services to model
       App.store.loadMany(this.get('model'), result);
@@ -356,7 +360,9 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({
           }
         } else if (hostComponent.component_name === 'HBASE_MASTER') {
           if (hostComponent.work_status === 'STARTED') {
-            (hostComponent.ha_status === true || hostComponent.ha_status == 'true') ?
+            //@TODO: Remove below consition when ambari-server supports returning HBase master HA status for assemblies
+            var isNoneCoreService = !App.StackService.find().mapProperty('serviceName').contains(hostComponent.service_id);
+            (hostComponent.ha_status === true || hostComponent.ha_status == 'true' || isNoneCoreService) ?
               hostComponent.display_name_advanced = this.t('dashboard.services.hbase.masterServer.active') :
               hostComponent.display_name_advanced = this.t('dashboard.services.hbase.masterServer.standby');
           } else {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index bcb7ca3..e5e6489 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -180,6 +180,7 @@ Em.I18n.translations = {
   'common.error': 'Error',
   'common.loading': 'Loading',
   'common.search': 'Search',
+  'common.search.small': 'search',
   'common.confirm': 'Confirm',
   'common.upgrade': 'Upgrade',
   'common.reUpgrade': 'Retry Upgrade',
@@ -272,6 +273,7 @@ Em.I18n.translations = {
   'common.property.undefined': "Undefined",
   'common.summary': "Summary",
   'common.configs': "Configs",
+  'common.settings': 'Settings',
   'common.configuration': "Configuration",
   'common.unknown': "Unknown",
   'common.install': "Install",
@@ -330,6 +332,13 @@ Em.I18n.translations = {
   'common.logs': 'Logs',
   'common.warn.message': '<div class="alert alert-warn">{0}</div>',
   'common.link': 'Link',
+  'common.categories': 'Categories',
+  'common.manage': 'Manage',
+  'common.deploying': 'Deploying...',
+  'common.state': 'State',
+  'common.uri': 'URI',
+  'common.hostName': 'HostName',
+  'common.ip': 'IP',
 
   'models.alert_instance.tiggered.verbose': "Occurred on {0} <br> Checked on {1}",
   'models.alert_definition.triggered.verbose': "Occurred on {0}",
@@ -1027,6 +1036,38 @@ Em.I18n.translations = {
   'form.validator.alertNotificationName':'Invalid Alert Notification Name. Only alphanumerics, hyphens, spaces and underscores are allowed.',
   'form.validator.configKey.specific':'"{0}" is invalid Key. Only alphanumerics, hyphens, underscores, asterisks and periods are allowed.',
 
+  'appStore.menu.header.discover': 'Discover',
+  'appStore.menu.header.manage': 'Manage',
+  'appStore.collections.header': 'Collections',
+  'appStore.collections.addToCollection': 'My Collection',
+  'appStore.collections.assemblies': 'My Assemblies',
+  'appStore.apps.title.assemblies': 'assemblies',
+  'appStore.apps.title.components': 'components',
+  'appStore.apps.title.assemblies.tooltip': 'Complex YARN application consists of more than one components',
+  'appStore.apps.title.components.tooltip': 'Simple YARN application consists of only one component',
+  'appStore.apps.noApps': 'No Assemblies and Components',
+  'assembly.manage.summary.description': 'Credit and Payment card fraud has mushroomed into a massive challenge for consumers, financial institutions, regulators and law inforcements',
+  'assembly.manage.summary.logsearch.description': 'Log Search assembly helps to do analysis, monitor and visualization of the aggregated log of distributed systems.',
+  'assembly.manage.summary.hbase.description': 'Apache HBase is an open source NoSQL database that provides real-time read/write access to large datasets.',
+  'assembly.manage.summary.zookeeper.description': 'Apache ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.',
+  'assembly.manage.summary.custom.description': 'This is a custom community certified assembly.',
+  'assembly.manage.summary.label.service': 'SERVICES',
+  'assembly.manage.summary.business.impact': 'BUSINESS IMPACT',
+  'assembly.manage.summary.quick.links': 'QUICK LINKS',
+  'assembly.manage.summary.yarn.ui.quick.link': 'Assembly Details (YARN UI)',
+  'assembly.manage.summary.grafana.quick.link': 'Assembly Dashboard (Grafana)',
+  'assembly.manage.assemblySpecFile': 'Assembly Spec File',
+  'assembly.manage.fraudTransactions': 'fraud transactions',
+  'assembly.manage.fraudCost': 'fraud cost in dollars',
+
+  'assembly.detailedInfo.infoTitle.assemblyName': 'assembly name',
+  'assembly.detailedInfo.infoTitle.uri': 'uri',
+  'assembly.detailedInfo.infoTitle.lifetime': 'lifetime',
+  'assembly.detailedInfo.infoTitle.expectedContainers': 'expected containers',
+  'assembly.detailedInfo.infoTitle.containers': 'containers',
+  'assembly.detailedInfo.containers.launchTime': 'Launch Time',
+  'assembly.detailedInfo.containers.bareHost': 'Bare Host',
+
   'alerts.add.header': 'Create Alert Definition',
   'alerts.add.step1.header': 'Choose Type',
   'alerts.add.step2.header': 'Configure',
@@ -2049,8 +2090,12 @@ Em.I18n.translations = {
   'services.service.startAll':'Start All',
   'services.service.stopAll':'Stop All',
   'services.service.restartAllRequired':'Restart All Required',
-  'services.service.startAll.confirmMsg' : 'You are about to start all services',
-  'services.service.stopAll.confirmMsg' : 'You are about to stop all services',
+  'services.service.core.startAll.confirmMsg' : 'You are about to start all core services',
+  'services.service.cluster.startAll.confirmMsg' : 'You are about to start all services for cluster',
+  'services.service.startAll.confirmMsg' : 'You are about to start all services for {0} assembly',
+  'services.service.core.stopAll.confirmMsg' : 'You are about to stop all core services',
+  'services.service.cluster.stopAll.confirmMsg' : 'You are about to stop all services for cluster',
+  'services.service.stopAll.confirmMsg' : 'You are about to stop all services for {0} assembly',
   'services.service.refreshAll.confirmMsg': '<p>You are about to restart {0}</p>' +
     '<div class="alert alert-warning">This will trigger alerts as the service is restarted. To suppress alerts, turn on Maintenance Mode for services listed above prior to running Restart All Required</div>',
   'services.service.start.confirmMsg' : 'You are about to start {0}',
@@ -2929,9 +2974,20 @@ Em.I18n.translations = {
   'menu.item.hosts':'Hosts',
   'menu.item.admin':'Admin',
   'menu.item.alerts': 'Alerts',
+  'menu.item.appStore': 'Assemblies',
   'menu.item.views':'<i class="icon-th"></i>',
   'menu.item.views.noViews':'No Views',
 
+  'assemblies.app.deploy.popup.description': ' We need a few configuration details',
+  'assemblies.app.deploy.popup.config.maxTransactions': 'Max. Transactions (per second)',
+  'assemblies.app.deploy.popup.config.maxAnalysts': 'Max. Analysts',
+
+  'assemblies.app.deploy.popup.logsearh.config.SourceComponents': 'Source Components',
+  'assemblies.app.deploy.popup.logsearch.config.logEvents': 'Log Events (per second)',
+
+
+  'assemblies.serviceGroups.menu.detailedInfo': 'Detailed Info',
+
   'bulkOperation.loading': 'Loading...',
   'jobs.nothingToShow': 'No jobs to display',
   'jobs.loadingTasks': 'Loading...',

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/mixins/common/widgets/widget_section.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/widgets/widget_section.js b/ambari-web/app/mixins/common/widgets/widget_section.js
index abd0c97..f82d739 100644
--- a/ambari-web/app/mixins/common/widgets/widget_section.js
+++ b/ambari-web/app/mixins/common/widgets/widget_section.js
@@ -72,14 +72,15 @@ App.WidgetSectionMixin = Ember.Mixin.create({
    */
   isServiceWithEnhancedWidgets: function () {
     var isServiceWithWidgetdescriptor;
-    var serviceName = this.get('content.serviceName');
+    var serviceName = this.get('content.stackServiceName');
+    var isCore = this.get('content.serviceGroupName') === 'CORE';
     if (serviceName) {
-      isServiceWithWidgetdescriptor = App.StackService.find().findProperty('serviceName', serviceName).get('isServiceWithWidgets');
+      isServiceWithWidgetdescriptor = App.StackService.find().findProperty('serviceName', serviceName).get('isServiceWithWidgets') && isCore;
     } else if (this.get('sectionName') === 'SYSTEM_HEATMAPS') {
       isServiceWithWidgetdescriptor = true;
     }
     return isServiceWithWidgetdescriptor;
-  }.property('content.serviceName'),
+  }.property('content.stackServiceName'),
 
   /**
    *  @Type {App.WidgetLayout}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/models.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models.js b/ambari-web/app/models.js
index b877255..6a54fc2 100644
--- a/ambari-web/app/models.js
+++ b/ambari-web/app/models.js
@@ -37,6 +37,7 @@ require('models/stack_service_component');
 require('models/quick_links');
 require('models/quicklinks/quick_links_config');
 require('models/service');
+require('models/service_group');
 require('models/service_audit');
 require('models/service/hdfs');
 require('models/service/yarn');
@@ -51,6 +52,9 @@ require('models/alerts/alert_instance_local');
 require('models/alerts/alert_notification');
 require('models/alerts/alert_config');
 require('models/alerts/alert_group');
+require('models/app_store/store_app');
+require('models/app_store/store_category');
+require('models/app_store/store_collection');
 require('models/user');
 require('models/host');
 require('models/rack');

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/models/app_store/store_app.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/app_store/store_app.js b/ambari-web/app/models/app_store/store_app.js
new file mode 100644
index 0000000..654397d
--- /dev/null
+++ b/ambari-web/app/models/app_store/store_app.js
@@ -0,0 +1,268 @@
+/**
+ * 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 = require('app');
+
+App.StoreApp = DS.Model.extend({
+  name: DS.attr('string'),
+  title: DS.attr('string', {defaultValue: ''}),
+  logoUrl: DS.attr('string'),
+  description: DS.attr('string', {defaultValue: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam eget vehicula elit, ac sollicitudin enim. Curabitur ullamcorper vitae est at convallis. Curabitur et lacus vehicula, imperdiet sapien nec, tempus metus.\n\nPellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam ut sapien leo. Quisque venenatis pellentesque erat, at auctor ipsum pulvinar ut.'}),
+  services: DS.attr('string'),
+  isActive: DS.attr('boolean'),
+  isComponent: DS.attr('boolean'),
+  storeCategories: DS.hasMany('App.StoreCategory'),
+  storeCollections: DS.hasMany('App.StoreCollection'),
+  configurations: DS.attr('array', {defaultValue:[{"name":Em.I18n.t('assemblies.app.deploy.popup.config.maxTransactions'),"minValue":100,"maxValue":100000,"step":100,"defaultValue":76000,"value":76000},{"name":Em.I18n.t('assemblies.app.deploy.popup.config.maxAnalysts'),"minValue":100,"maxValue":100000,"step":100,"defaultValue":300,"value":300}]}),
+
+  /**
+   * @type {boolean}
+   */
+  someConfigurationInvalid: function () {
+    return this.get('configurations').someProperty('errorMessage');
+  }.property('configurations.@each.errorMessage'),
+
+  init: function () {
+    this._super();
+    var configurations = this.get('configurations');
+    this.set('initConfigurations', JSON.parse(JSON.stringify(configurations)));
+  }
+
+});
+
+App.StoreApp.FIXTURES = [
+  {
+    id: 1,
+    name: 'Credit Fraud Detection',
+    title: 'Credit Fraud Detection with Apache NiFi',
+    logo_url: '/img/nifi-color.png',
+    services: 'HBASE | KAFKA | STORM | ZOOKEEPER',
+    is_active: false,
+    is_component: false,
+    description: 'Apache NiFi Eases Dataflow Management & Accelerates Time to Analytics in Banking.\n\nNiFi enables simple, fast data acquisition, secure data transport, prioritized data flow and clear traceability of data from the very edge of customer applications and endpoints all the way to the core data center.',
+    configurations: [
+      {
+        name: Em.I18n.t('assemblies.app.deploy.popup.config.maxTransactions'),
+        minValue: 100,
+        maxValue: 100000,
+        step: 100,
+        defaultValue: 76000,
+        value: 76000
+      },
+      {
+        name: Em.I18n.t('assemblies.app.deploy.popup.config.maxAnalysts'),
+        minValue: 100,
+        maxValue: 100000,
+        step: 100,
+        defaultValue: 300,
+        value: 300
+      }
+    ],
+    store_categories: [4],
+    store_collections: [1]
+  },
+  {
+    id: 2,
+    name: 'Log Search',
+    title: 'Log Search with Apache Solr',
+    logo_url: '/img/solr-color.png',
+    services: 'ZOOKEEPER | LOG SEARCH',
+    is_active: false,
+    is_component: false,
+    description: Em.I18n.t('assembly.manage.summary.logsearch.description') + "\n\nSolr is highly reliable, scalable and fault tolerant, providing distributed indexing, replication and load-balanced querying, automated failover and recovery, centralized configuration and more. Solr powers the search and navigation features of many of the world's largest internet sites.",
+    store_categories: [6],
+    store_collections: [],
+    configurations: [
+      {
+        name: Em.I18n.t('assemblies.app.deploy.popup.logsearh.config.SourceComponents'),
+        minValue: 1,
+        maxValue: 10000,
+        step: 100,
+        defaultValue: 1000,
+        value: 1000
+      },
+      {
+        name: Em.I18n.t('assemblies.app.deploy.popup.logsearch.config.logEvents'),
+        minValue: 100,
+        maxValue: 300000,
+        step: 100,
+        defaultValue: 150000,
+        value: 150000
+      }
+    ]
+  },
+  {
+    id: 3,
+    name: 'Apache Metron',
+    logo_url: '/img/metron-color.png',
+    services: 'HBASE | ACCUMULO | ZOOKEEPER',
+    is_active: false,
+    is_component: false,
+    description: 'Apache Metron is the next evolution of Security Incident Event Management.\nMetron helps users process unprecedented volumes of data per second, changing the game for malware detection and prevention. When an organization is attacked, Metron users can process and compare data from comprehensive feeds across the platform in real time. This not only facilitates enhanced detection of malware campaigns, but also impacts the economics for attackers by requiring them to customize malware for each target. ',
+    store_categories: [4],
+    store_collections: [1]
+  },
+  {
+    id: 4,
+    name: 'ETL in 1 Hour',
+    logo_url: '/img/sqoop-color.png',
+    services: 'SQOOP | OOZIE',
+    is_active: false,
+    is_component: false,
+    description: 'Sqoop is a command-line interface application for transferring data between relational databases and Hadoop.\n It supports incremental loads of a single table or a free form SQL query as well as saved jobs which can be run multiple times to import updates made to a database since the last import. Imports can also be used to populate tables in Hive or HBase.',
+    store_categories: [3],
+    store_collections: []
+  },
+  {
+    id: 5,
+    name: 'Backups',
+    logo_url: '/img/falcon-color.png',
+    services: 'KAFKA | STORM | ZOOKEEPER',
+    is_active: false,
+    is_component: false,
+    store_categories: [3],
+    store_collections: []
+  },
+  {
+    id: 6,
+    name: 'Prediction',
+    logo_url: '/img/spark-color.png',
+    services: 'HBASE | ACCUMULO | ZOOKEEPER',
+    is_active: false,
+    is_component: false,
+    store_categories: [6],
+    store_collections: []
+  },
+  {
+    id: 7,
+    name: 'Broker Mgmt',
+    logo_url: '/img/metron-color.png',
+    services: 'HBASE | ACCUMULO | ZOOKEEPER',
+    is_active: false,
+    is_component: false,
+    store_categories: [7],
+    store_collections: []
+  },
+  {
+    id: 8,
+    name: 'Configuration',
+    logo_url: '/img/storm-color.png',
+    services: 'HBASE | ACCUMULO | ZOOKEEPER',
+    is_active: false,
+    is_component: false,
+    store_categories: [3],
+    store_collections: []
+  },
+  {
+    id: 9,
+    name: 'Caching',
+    logo_url: '/img/memcache-color.png',
+    services: 'HBASE | ACCUMULO | ZOOKEEPER',
+    is_active: false,
+    is_component: false,
+    store_categories: [4],
+    store_collections: []
+  },
+  {
+    id: 10,
+    name: 'Fast Retrieval',
+    logo_url: '/img/accumulo-color.png',
+    services: 'HBASE | ACCUMULO | ZOOKEEPER',
+    is_active: false,
+    is_component: false,
+    store_categories: [6],
+    store_collections: []
+  },
+  {
+    id: 11,
+    name: 'Apache HBase',
+    logo_url: '/img/hbase-color.png',
+    is_active: false,
+    services: [],
+    is_component: true,
+    description: 'Apache HBase is an open source, non-relational, distributed database. \nHBase features compression, in-memory operation, and Bloom filters on a per-column basis as outlined in the original BigTable paper. Tables in HBase can serve as the input and output for MapReduce jobs run in Hadoop, and may be accessed through the Java API but also through REST, Avro or Thrift gateway APIs. ',
+    store_categories: [7],
+    store_collections: [1]
+  },
+  {
+    id: 12,
+    name: 'Apache Storm',
+    logo_url: '/img/storm-color.png',
+    is_active: false,
+    services: [],
+    is_component: true,
+    description: 'Apache Storm is a distributed computation framework written predominantly in the Clojure programming language.\n Originally created by Nathan Marz and team at BackType, the project was open sourced after being acquired by Twitter. It uses custom created "spouts" and "bolts" to define information sources and manipulations to allow batch, distributed processing of streaming data.',
+    store_categories: [3],
+    store_collections: [1]
+  },
+  {
+    id: 13,
+    name: 'Jenkins',
+    logo_url: '/img/jenkins-color.png',
+    is_active: false,
+    services: [],
+    is_component: true,
+    description: 'Jenkins is an open source continuous integration tool written in Java.\nJenkins provides continuous integration services for software development. It is a server-based system running in a servlet container such as Apache Tomcat. It supports SCM tools including AccuRev, CVS, Subversion, Git, Mercurial, Perforce, Clearcase and RTC, and can execute Apache Ant and Apache Maven based projects as well as arbitrary shell scripts and Windows batch commands.',
+    store_categories: [6],
+    store_collections: []
+  },
+  {
+    id: 14,
+    name: 'Apache Kafka',
+    logo_url: '/img/kafka-color.png',
+    is_active: false,
+    services: [],
+    is_component: true,
+    description: 'Apache Kafka is an open-source message broker project developed by the Apache Software Foundation written in Scala.\n The project aims to provide a unified, high-throughput, low-latency platform for handling real-time data feeds. It is, in its essence, a "massively scalable pub/sub message queue architected as a distributed transaction log", making it highly valuable for enterprise infrastructures.',
+    store_categories: [7],
+    store_collections: [1]
+  },
+  {
+    id: 15,
+    name: 'Apache Spark',
+    logo_url: '/img/spark-color.png',
+    is_active: false,
+    services: [],
+    is_component: true,
+    description: 'Apache Spark provides programmers with an application programming interface centered on a data structure called the resilient distributed dataset (RDD), a read-only multiset of data items distributed over a cluster of machines, that is maintained in a fault-tolerant way.\n It was developed in response to limitations in the MapReduce cluster computing paradigm, which forces a particular linear dataflow structure on distributed programs.',
+    store_categories: [6],
+    store_collections: []
+  },
+  {
+    id: 16,
+    name: 'Apache Solr',
+    logo_url: '/img/solr-color.png',
+    is_active: false,
+    services: [],
+    is_component: true,
+    description: 'Solr (pronounced "solar") is an open source enterprise search platform, written in Java, from the Apache Lucene project.\n Its major features include full-text search, hit highlighting, faceted search, real-time indexing, dynamic clustering, database integration, NoSQL features and rich document (e.g., Word, PDF) handling.',
+    store_categories: [6],
+    store_collections: []
+  },
+  {
+    id: 17,
+    name: 'ZooKeeper',
+    logo_url: '/img/zookeeper-color.png',
+    is_active: false,
+    services: [],
+    is_component: true,
+    description: 'ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.\n All of these kinds of services are used in some form or another by distributed applications. Each time they are implemented there is a lot of work that goes into fixing the bugs and race conditions that are inevitable.',
+    store_categories: [6],
+    store_collections: []
+  }
+];
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/models/app_store/store_category.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/app_store/store_category.js b/ambari-web/app/models/app_store/store_category.js
new file mode 100644
index 0000000..a086d99
--- /dev/null
+++ b/ambari-web/app/models/app_store/store_category.js
@@ -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.
+ */
+
+var App = require('app');
+
+App.StoreCategory = DS.Model.extend({
+
+  name: DS.attr('string'),
+  isActive: DS.attr('boolean'),
+  storeApps: DS.hasMany('App.StoreApp')
+
+});
+
+App.StoreCategory.FIXTURES = [
+  {id: 1, name: 'All', is_active: false, store_apps: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]},
+  {id: 2, name: 'Access', is_active: false, store_apps: []},
+  {id: 3, name: 'Data Movement', is_active: false, store_apps: [4, 5, 8, 12]},
+  {id: 4, name: 'Security', is_active: false, store_apps: [1, 3, 9]},
+  {id: 5, name: 'Governance', is_active: false, store_apps: []},
+  {id: 6, name: 'Operations', is_active: false, store_apps: [2, 6, 10, 11, 13, 15, 16, 17]},
+  {id: 7, name: 'Storage', is_active: false, store_apps: [7, 14]}
+];
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/models/app_store/store_collection.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/app_store/store_collection.js b/ambari-web/app/models/app_store/store_collection.js
new file mode 100644
index 0000000..c6b46c0
--- /dev/null
+++ b/ambari-web/app/models/app_store/store_collection.js
@@ -0,0 +1,31 @@
+/**
+ * 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 = require('app');
+
+App.StoreCollection = DS.Model.extend({
+
+  name: DS.attr('string'),
+  isActive: DS.attr('boolean'),
+  storeApps: DS.hasMany('App.StoreApp')
+
+});
+
+App.StoreCollection.FIXTURES = [
+  {id: 1, name: 'Manage My System', store_apps: [1, 3, 11, 12], is_active: false}
+];
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/models/service.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/service.js b/ambari-web/app/models/service.js
index c648e93..da04f6a 100644
--- a/ambari-web/app/models/service.js
+++ b/ambari-web/app/models/service.js
@@ -22,13 +22,16 @@ require('utils/config');
 
 App.Service = DS.Model.extend({
   serviceName: DS.attr('string'),
-  displayName: Em.computed.formatRole('serviceName', true),
+  displayName: Em.computed.formatRole('stackServiceName', true),
+  stackServiceName: DS.attr('string'),
+  serviceGroupName: DS.attr('string'),
   passiveState: DS.attr('string'),
   workStatus: DS.attr('string'),
   rand: DS.attr('string'),
   toolTipContent: DS.attr('string'),
   quickLinks: DS.hasMany('App.QuickLinks'),  // mapped in app/mappers/service_metrics_mapper.js method - mapQuickLinks
   hostComponents: DS.hasMany('App.HostComponent'),
+  serviceGroup: DS.belongsTo('App.ServiceGroup'),
   serviceConfigsTemplate: App.config.get('preDefinedServiceConfigs'),
   /**
    * used by services("OOZIE", "ZOOKEEPER", "HIVE", "MAPREDUCE2", "TEZ", "SQOOP", "PIG","FALCON")
@@ -165,7 +168,14 @@ App.Service = DS.Model.extend({
    * Number of the Critical and Warning alerts for current service
    * @type {number}
    */
-  alertsCount: 0
+  alertsCount: 0,
+
+  /**
+   *
+   */
+  logo: function() {
+    return App.Service.logo[this.get('stackServiceName')];
+  }.property('id')
 
 });
 
@@ -251,3 +261,18 @@ App.Service.extendedModel = {
 };
 
 App.Service.FIXTURES = [];
+
+App.Service.logo = {
+  'NIFI': '/img/nifi-color.png',
+  'CFMON': '/img/cfmon-color.png',
+  'LOGSEARCH': '/img/solr-color.png',
+  'SQOOP':'/img/sqoop-color.png',
+  'FALCON':'/img/falcon-color.png',
+  'SPARK':'/img/spark-color.png',
+  'SPARK2':'/img/spark-color.png',
+  'STORM':'/img/storm-color.png',
+  'ACCUMULO':'/img/accumulo-color.png',
+  'HBASE':'/img/hbase-color.png',
+  'ZOOKEEPER':'/img/zookeeper-color.png',
+  'KAFKA':'/img/kafka-color.png'
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/models/service_group.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/service_group.js b/ambari-web/app/models/service_group.js
new file mode 100644
index 0000000..532f1d3
--- /dev/null
+++ b/ambari-web/app/models/service_group.js
@@ -0,0 +1,270 @@
+/**
+ * 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 = require('app');
+
+App.ServiceGroup = DS.Model.extend({
+  clusterName: DS.attr('string'),
+  serviceGroupName: DS.attr('string'),
+  serviceGroupDisplayName: DS.attr('string'),
+  serviceGroupType: DS.attr('string'),
+  currentState: DS.attr('string'),
+  desiredState: DS.attr('string'),
+  assemblyFile: DS.attr('string'),
+  quicklinks: DS.attr('object'),
+  applicationId: DS.attr('string'),
+  lifetime: DS.attr('string'),
+  services: DS.hasMany('App.Service'),
+  isActive: false,
+
+  containers: DS.attr('object'),
+
+  businessImpact: {
+    fraudTransactions: 46,
+    fraudCost: '23,000'
+  },
+
+  configurations: function() {
+    var serviceMetaData = App.ServiceGroup.metadata[this.get('serviceGroupDisplayName')];
+    if (serviceMetaData && serviceMetaData.configurations) {
+      return serviceMetaData.configurations;
+    } else {
+      return App.ServiceGroup.metadata["Credit Fraud Detection"].configurations;
+    }
+  }.property('id'),
+
+  description : function() {
+    var serviceMetaData = App.ServiceGroup.metadata[this.get('serviceGroupDisplayName')];
+    if (serviceMetaData) {
+      return serviceMetaData.description;
+    } else {
+      return Em.I18n.t('assembly.manage.summary.custom.description');
+    }
+  }.property('id'),
+
+  /**
+   * @type {string}
+   */
+  serviceGroupNameLower: function () {
+    return (this.get('serviceGroupName') || '').toLowerCase();
+  }.property('serviceGroupName'),
+
+  /**
+   * @type {string}
+   */
+  uri: Em.computed.format('/services/v1/applications/{0}', 'serviceGroupNameLower'),
+
+  /**
+   * @type {number}
+   */
+  alertsCount: Em.computed.sumBy('services', 'alertsCount'),
+
+  /**
+   * @type {number|string}
+   */
+  shownAlertsCount: function () {
+    var alertsCount = this.get('alertsCount');
+    return alertsCount > 99 ? '99+' : alertsCount;
+  }.property('alertsCount'),
+
+  /**
+   * @type {boolean}
+   */
+  isStopped: Em.computed.equal('desiredState', 'INSTALLED'),
+
+  /**
+   * @type {boolean}
+   */
+  isStarted: Em.computed.equal('desiredState', 'STARTED'),
+
+  /**
+   * Should "Start All"-button be disabled
+   * @type {bool}
+   */
+  isStartAllDisabled: Em.computed.or('isStartStopAllClicked', '!someServiceIsStopped'),
+
+  /**
+   * @type {boolean}
+   */
+  someServiceIsStopped: function () {
+    return this.get('services').filter(function (_service) {
+        return _service.get('healthStatus') === 'red' && !App.get('services.clientOnly').contains(_service.get('serviceName'));
+      }).length > 0;
+  }.property('services.@each.healthStatus'),
+
+  /**
+   * Should "Stop All"-button be disabled
+   * @type {bool}
+   */
+  isStopAllDisabled: Em.computed.or('isStartStopAllClicked', '!someServiceIsStarted'),
+
+  /**
+   * @type {boolean}
+   */
+  someServiceIsStarted: Em.computed.someBy('services', 'healthStatus', 'green'),
+
+  /**
+   * @type {boolean}
+   */
+  allServicesAreStarted: Em.computed.everyBy('services', 'healthStatus', 'green'),
+
+  /**
+   * Should "Refresh All"-button be disabled
+   * @type {bool}
+   */
+  isRestartAllRequiredDisabled: Em.computed.everyBy('services', 'isRestartRequired', false),
+
+  /**
+   * @type {bool}
+   */
+  isStartStopAllClicked: Em.computed.notEqual('App.router.backgroundOperationsController.allOperationsCount', 0),
+
+  /**
+   * Check if all services are installed
+   * true - all installed, false - not all
+   * @type {bool}
+   */
+  isAllServicesInstalled: function () {
+    var sLength = this.get('services.content.length');
+    if (!sLength) return false;
+    var availableServices = App.StackService.find().mapProperty('serviceName');
+    return sLength === availableServices.length;
+  }.property('services.[]', 'services.content.length'),
+
+  /**
+   * Check if Core service group
+   * true - all installed, false - not all
+   * @type {bool}
+   */
+  isCoreServiceGroup: Em.computed.equal('serviceGroupName', 'CORE'),
+
+  /**
+   * Check if CF-MONITOR service group
+   * true - all installed, false - not all
+   * @type {bool}
+   */
+  isCfMonitorServiceGroup: Em.computed.equal('serviceGroupDisplayName', 'Credit Fraud Detection'),
+
+  /**
+   * @type {boolean}
+   */
+  someConfigurationInvalid: function () {
+    return this.get('configurations').someProperty('errorMessage');
+  }.property('configurations.@each.errorMessage'),
+
+  init: function () {
+    this._super();
+    var configurations = this.get('configurations');
+    this.set('initConfigurations', JSON.parse(JSON.stringify(configurations)));
+  },
+
+  assemblyLinks: function() {
+    var quickLinks = [];
+    var yarnService = App.YARNService.find().objectAt(0);
+    if (yarnService) {
+      var activeRm = yarnService.get('hostComponents').filterProperty('componentName', 'RESOURCEMANAGER').findProperty('haStatus', 'ACTIVE');
+      if (activeRm) {
+        var activeRmHostName = activeRm.get('hostName');
+        var applicationLink = 'http://' + activeRmHostName + ':8088/proxy/' + this.get('applicationId') ;
+        var YarnLinkObject = {
+          label: Em.I18n.t('assembly.manage.summary.yarn.ui.quick.link'),
+          url: applicationLink
+        };
+        quickLinks.pushObject(YarnLinkObject);
+      }
+    }
+    if (this.get('isCfMonitorServiceGroup')) {
+      var grafanaLinkObject = {
+        label: Em.I18n.t('assembly.manage.summary.grafana.quick.link'),
+        url: 'http://cn005.l42scl.hortonworks.com:3000/dashboard/db/cf-monitor'
+      };
+      quickLinks.pushObject(grafanaLinkObject);
+    }
+    var componentLinks = this.get('quicklinks');
+    if (!Em.isNone(componentLinks)) {
+      Object.keys(componentLinks).forEach(function (key) {
+        var value = componentLinks[key];
+        quickLinks.pushObject({
+          label: key,
+          url: value
+        });
+      }, this);
+    }
+    return quickLinks;
+  }.property('App.router.clusterController.isServiceMetricsLoaded', 'serviceGroupName')
+
+});
+
+App.ServiceGroup.FIXTURES = [];
+
+App.ServiceGroup.displayOrder = [
+  'Credit Fraud Detection',
+  'Logsearch Stable'
+];
+
+App.ServiceGroup.metadata = {
+  "Credit Fraud Detection": {
+    description: Em.I18n.t('assembly.manage.summary.description'),
+    configurations: [
+      {
+        name: Em.I18n.t('assemblies.app.deploy.popup.config.maxTransactions'),
+        minValue: 100,
+        maxValue: 100000,
+        step: 100,
+        defaultValue: 76000,
+        value: 76000
+      },
+      {
+        name: Em.I18n.t('assemblies.app.deploy.popup.config.maxAnalysts'),
+        minValue: 100,
+        maxValue: 100000,
+        step: 100,
+        defaultValue: 300,
+        value: 300
+      }
+    ]
+  },
+  "Logsearch Stable": {
+    description: Em.I18n.t('assembly.manage.summary.logsearch.description'),
+    configurations: [
+      {
+        name: Em.I18n.t('assemblies.app.deploy.popup.logsearh.config.SourceComponents'),
+        minValue: 1,
+        maxValue: 10000,
+        step: 100,
+        defaultValue: 1000,
+        value: 1000
+      },
+      {
+        name: Em.I18n.t('assemblies.app.deploy.popup.logsearch.config.logEvents'),
+        minValue: 100,
+        maxValue: 300000,
+        step: 100,
+        defaultValue: 150000,
+        value: 150000
+      }
+    ]
+  },
+  "HBase Stable": {
+    description: Em.I18n.t('assembly.manage.summary.hbase.description')
+  },
+  "Vinod's Zookeeper": {
+    description: Em.I18n.t('assembly.manage.summary.zookeeper.description')
+  }
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/router.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/router.js b/ambari-web/app/router.js
index 496e3d3..30adb60 100644
--- a/ambari-web/app/router.js
+++ b/ambari-web/app/router.js
@@ -86,6 +86,13 @@ App.Router = Em.Router.extend({
    */
   preferedPath: null,
 
+  /**
+   * @type {boolean}
+   */
+  isAppStorePageSelected: function() {
+    return this.get('currentState.path').indexOf('main.assemblies') !== -1;
+  }.property('currentState.path'),
+
   setNavigationFlow: function (step) {
     var matches = step.match(/\d+$/);
     var newStep;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/routes/main.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js
index fba3410..f622490 100644
--- a/ambari-web/app/routes/main.js
+++ b/ambari-web/app/routes/main.js
@@ -17,7 +17,6 @@
  */
 
 var App = require('app');
-var stringUtils = require('utils/string_utils');
 
 module.exports = Em.Route.extend(App.RouterRedirections, {
   route: '/main',
@@ -79,18 +78,6 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
       }
     });
   },
-  /*
-   routePath: function(router,event) {
-   if (router.getAuthenticated()) {
-   App.router.get('clusterController').loadClusterName(false);
-   router.get('mainController').initialize();
-   // TODO: redirect to last known state
-   } else {
-   Ember.run.next(function () {
-   router.transitionTo('login');
-   });
-   }
-   }, */
 
   index: Ember.Route.extend({
     route: '/',
@@ -187,6 +174,151 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
   views: require('routes/views'),
   view: require('routes/view'),
 
+  assemblies: Em.Route.extend({
+    route: '/assemblies',
+
+    connectOutlets: function(router) {
+      router.get('mainController').connectOutlet('mainAssemblies');
+    },
+
+    index: Em.Route.extend({
+      route: '/',
+      enter: function (router) {
+        router.transitionTo('categories.index');
+      }
+    }),
+
+    categories: Em.Route.extend({
+      exit: function () {
+        App.StoreCategory.find().setEach('isActive', false);
+      },
+      route: '/categories',
+      index: Em.Route.extend({
+        route: '/',
+        enter: function (router) {
+          Em.run.next(function () {
+            var storeCategories = App.StoreCategory.find();
+            storeCategories.setEach('isActive', false);
+            var storeCategory = storeCategories.findProperty('name', 'All');
+            storeCategory.set('isActive',true);
+            router.transitionTo('categories.details', storeCategory);
+          });
+        },
+        connectOutlets: function (router) {
+          var controller = router.get('mainAssembliesController');
+          controller.set('showFilterString', true);
+          controller.connectOutlet('mainAssembliesCategories');
+        }
+      }),
+
+      details: Em.Route.extend({
+        route: '/:store_category_id',
+        connectOutlets: function (router, store_category) {
+          router.get('mainController').dataLoading().done(function () {
+            App.StoreCategory.find().setEach('isActive', false);
+            store_category.set('isActive', true);
+            router.get('mainAssembliesController').connectOutlet('mainAssembliesCategory', store_category);
+            router.get('mainAssembliesCategoryController').propertyDidChange('filteredStoreApps');
+          });
+        }
+      })
+    }),
+
+    collections: Em.Route.extend({
+      exit: function () {
+        App.StoreCollection.find().setEach('isActive', false);
+      },
+      route: '/collections',
+      index: Em.Route.extend({
+        route: '/',
+        connectOutlets: function (router) {
+          var controller = router.get('mainAssembliesController');
+          controller.set('showFilterString', true);
+          controller.connectOutlet('mainAssembliesCollections');
+        }
+      }),
+
+      details: Em.Route.extend({
+        route: '/:store_collection_id',
+        connectOutlets: function (router, store_collection) {
+          App.StoreCollection.find().setEach('isActive', false);
+          store_collection.set('isActive', true);
+          router.get('mainAssembliesController').connectOutlet('mainAssembliesCollection', store_collection);
+          router.get('mainAssembliesCollectionController').propertyDidChange('filteredStoreApps');
+        }
+      })
+    }),
+
+    serviceGroups: Em.Route.extend({
+      route: '/service-groups',
+      enter: function (router) {
+        router.get('mainAssembliesController').set('showFilterString', false);
+      },
+      exit: function (router) {
+        App.ServiceGroup.find().setEach('isActive', false);
+        router.get('mainAssembliesController').set('showFilterString', true);
+      },
+      index: Em.Route.extend({
+        route: '/',
+        connectOutlets: function (router) {
+          router.get('mainAssembliesController').connectOutlet('mainAssembliesServiceGroups');
+        }
+      }),
+      details: Em.Route.extend({
+        route: '/:service_group_id',
+
+        connectOutlets: function (router, service_group) {
+          router.get('mainController').dataLoading().done(function () {
+            var serviceGroup = App.ServiceGroup.find(service_group.get('id'));
+            router.get('mainAssembliesController').connectOutlet('mainAssembliesServiceGroup', serviceGroup);
+              router.transitionTo('summary');
+          });
+        },
+
+        index: Em.Route.extend({
+          route: '/'
+        }),
+
+        summary: Em.Route.extend({
+          route: '/summary',
+          connectOutlets: function (router) {
+            router.get('mainController').dataLoading().done(function () {
+              var serviceGroup =  router.get('mainAssembliesServiceGroupController.content');
+              var assembliesController = App.router.get('mainAssembliesController');
+              assembliesController.set('activeServiceGroupId', serviceGroup.get('id'));
+              Em.run.later(function () {
+                var appStoreEl = $("#apps-store");
+                if (appStoreEl) {
+                  assembliesController.closeNonServiceGroupsPanels();
+                  var deployedAssembliesEl = appStoreEl.find("#manage-deployed-assemblies-label");
+                  var deployedAssembliesContent = appStoreEl.find("#manage-deployed-assemblies-content");
+                  if (!deployedAssembliesContent.hasClass('in')) {
+                    deployedAssembliesEl.trigger('click');
+                  }
+                }
+              }, 1500);
+              router.get('mainAssembliesServiceGroupController').connectOutlet('mainAssembliesServiceGroupSummary', serviceGroup);
+            });
+          }
+        }),
+
+        settings: Em.Route.extend({
+          route: '/settings',
+          connectOutlets: function (router) {
+            router.get('mainAssembliesServiceGroupController').connectOutlet('mainAssembliesServiceGroupConfigs', router.get('mainAssembliesServiceGroupController.content'));
+          }
+        }),
+
+        detailedInfo: Em.Route.extend({
+          route: '/detailed-info',
+          connectOutlets: function (router) {
+            router.get('mainAssembliesServiceGroupController').connectOutlet('mainAssembliesServiceGroupDetailedInfo', router.get('mainAssembliesServiceGroupController.content'));
+          }
+        })
+      })
+    })
+
+  }),
 
   hosts: Em.Route.extend({
     route: '/hosts',
@@ -642,18 +774,24 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
     service: Em.Route.extend({
       route: '/:service_id',
       connectOutlets: function (router, service) {
-        router.get('mainServiceController').connectOutlet('mainServiceItem', service);
-        if (service.get('isLoaded')) {
-          if (router.get('mainServiceItemController').get('routeToConfigs')) {
-            router.transitionTo('configs');
-          } else if (router.get('mainServiceItemController.routeToHeatmaps')) {
-            router.transitionTo('heatmaps');
+        var controller = router.get('mainController');
+        controller.dataLoading().done(function () {
+          var mainServiceController = router.get('mainServiceController');
+          var serviceGroup = App.ServiceGroup.find().findProperty('id', service.get('serviceGroupName'));
+          mainServiceController.set('serviceGroup', serviceGroup);
+          router.get('mainServiceController').connectOutlet('mainServiceItem', service);
+          if (service.get('isLoaded')) {
+            if (router.get('mainServiceItemController').get('routeToConfigs')) {
+              router.transitionTo('configs');
+            } else if (router.get('mainServiceItemController.routeToHeatmaps')) {
+              router.transitionTo('heatmaps');
+            } else {
+              router.transitionTo('summary');
+            }
           } else {
-            router.transitionTo('summary');
+            router.transitionTo('index');
           }
-        } else {
-          router.transitionTo('index');
-        }
+        });
       },
       index: Ember.Route.extend({
         route: '/'
@@ -661,15 +799,18 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
       summary: Em.Route.extend({
         route: '/summary',
         connectOutlets: function (router, context) {
-          App.loadTimer.start('Service Summary Page');
-          var item = router.get('mainServiceItemController.content');
-          if (router.get('clusterController.isServiceMetricsLoaded')) router.get('updateController').updateServiceMetric(Em.K);
-          //if service is not existed then route to default service
-          if (item.get('isLoaded')) {
-            router.get('mainServiceItemController').connectOutlet('mainServiceInfoSummary', item);
-          } else {
-            router.transitionTo('services.index');
-          }
+          var controller = router.get('mainController');
+          controller.dataLoading().done(function () {
+            App.loadTimer.start('Service Summary Page');
+            var item = router.get('mainServiceItemController.content');
+            if (router.get('clusterController.isServiceMetricsLoaded')) router.get('updateController').updateServiceMetric(Em.K);
+            //if service is not existed then route to default service
+            if (item.get('isLoaded')) {
+              router.get('mainServiceItemController').connectOutlet('mainServiceInfoSummary', item);
+            } else {
+              router.transitionTo('services.index');
+            }
+          });
         }
       }),
       metrics: Em.Route.extend({
@@ -773,7 +914,8 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
     router.transitionTo('hosts.hostDetails.index', event.context);
   },
   filterHosts: function (router, component) {
-    if (!component.context)
+    var serviceGroupName = component.context.get('service.serviceGroupName');
+    if (!component.context || (serviceGroupName && serviceGroupName !== 'CORE'))
       return;
     router.get('mainHostController').filterByComponent(component.context);
     router.get('mainHostController').set('showFilterConditionsFirstLoad', true);
@@ -781,9 +923,11 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
     router.transitionTo('hosts.index');
   },
   showDetails: function (router, event) {
-    router.get('mainHostDetailsController').set('referer', router.location.lastSetURL);
-    router.get('mainHostDetailsController').set('isFromHosts', true);
-    router.transitionTo('hosts.hostDetails.summary', event.context);
+    if (event.context && App.Host.find().mapProperty('id').contains(event.context.get('id'))) {
+      router.get('mainHostDetailsController').set('referer', router.location.lastSetURL);
+      router.get('mainHostDetailsController').set('isFromHosts', true);
+      router.transitionTo('hosts.hostDetails.summary', event.context);
+    }
   },
   gotoAlertDetails: function (router, event) {
     router.transitionTo('alerts.alertDetails', event.context);


[15/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSParser.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSParser.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSParser.java
new file mode 100644
index 0000000..e465276
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSParser.java
@@ -0,0 +1,184 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.atsJobs;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Parser of ATS responses
+ */
+public class ATSParser implements IATSParser {
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(ATSParser.class);
+
+  private ATSRequestsDelegate delegate;
+
+  private static final long MillisInSecond = 1000L;
+
+  public ATSParser(ATSRequestsDelegate delegate) {
+    this.delegate = delegate;
+  }
+
+  @Override
+  public List<HiveQueryId> getHiveQueryIdsList(String username) {
+    JSONObject entities = delegate.hiveQueryIdList(username);
+    JSONArray jobs = (JSONArray) entities.get("entities");
+
+    List<HiveQueryId> parsedJobs = new LinkedList<HiveQueryId>();
+    for(Object job : jobs) {
+      try {
+        HiveQueryId parsedJob = parseAtsHiveJob((JSONObject) job);
+        parsedJobs.add(parsedJob);
+      } catch (Exception ex) {
+        LOG.error("Error while parsing ATS job", ex);
+      }
+    }
+
+    return parsedJobs;
+  }
+
+  @Override
+  public List<TezVertexId> getVerticesForDAGId(String dagId) {
+    JSONObject entities = delegate.tezVerticesListForDAG(dagId);
+    JSONArray vertices = (JSONArray) entities.get("entities");
+
+    List<TezVertexId> parsedVertices = new LinkedList<TezVertexId>();
+    for(Object vertex : vertices) {
+      try {
+        TezVertexId parsedVertex = parseVertex((JSONObject) vertex);
+        parsedVertices.add(parsedVertex);
+      } catch (Exception ex) {
+        LOG.error("Error while parsing the vertex", ex);
+      }
+    }
+
+    return parsedVertices;
+  }
+
+  @Override
+  public HiveQueryId getHiveQueryIdByOperationId(String guidString) {
+    JSONObject entities = delegate.hiveQueryIdByOperationId(guidString);
+    JSONArray jobs = (JSONArray) entities.get("entities");
+
+    assert jobs.size() <= 1;
+    if (jobs.size() == 0) {
+      return new HiveQueryId();
+    }
+
+    return parseAtsHiveJob((JSONObject) jobs.get(0));
+  }
+
+  @Override
+  public TezDagId getTezDAGByName(String name) {
+    JSONArray tezDagEntities = (JSONArray) delegate.tezDagByName(name).get("entities");
+    return parseTezDag(tezDagEntities);
+  }
+
+  @Override
+  public TezDagId getTezDAGByEntity(String entity) {
+    JSONArray tezDagEntities = (JSONArray) delegate.tezDagByEntity(entity).get("entities");
+    return parseTezDag(tezDagEntities);
+  }
+
+  private TezDagId parseTezDag(JSONArray tezDagEntities) {
+    assert tezDagEntities.size() <= 1;
+    if (tezDagEntities.size() == 0) {
+      return new TezDagId();
+    }
+    JSONObject tezDagEntity = (JSONObject) tezDagEntities.get(0);
+
+    TezDagId parsedDag = new TezDagId();
+    JSONArray applicationIds = (JSONArray) ((JSONObject) tezDagEntity.get("primaryfilters")).get("applicationId");
+    parsedDag.entity = (String) tezDagEntity.get("entity");
+    parsedDag.applicationId = (String) applicationIds.get(0);
+    parsedDag.status = (String) ((JSONObject) tezDagEntity.get("otherinfo")).get("status");
+    return parsedDag;
+  }
+
+  private HiveQueryId parseAtsHiveJob(JSONObject job) {
+    HiveQueryId parsedJob = new HiveQueryId();
+
+    parsedJob.entity = (String) job.get("entity");
+    parsedJob.url = delegate.hiveQueryIdDirectUrl((String) job.get("entity"));
+    parsedJob.starttime = ((Long) job.get("starttime")) / MillisInSecond;
+
+    JSONObject primaryfilters = (JSONObject) job.get("primaryfilters");
+    JSONArray operationIds = (JSONArray) primaryfilters.get("operationid");
+    if (operationIds != null) {
+      parsedJob.operationId = (String) (operationIds).get(0);
+    }
+    JSONArray users = (JSONArray) primaryfilters.get("user");
+    if (users != null) {
+      parsedJob.user = (String) (users).get(0);
+    }
+
+    JSONObject lastEvent = getLastEvent(job);
+    long lastEventTimestamp = ((Long) lastEvent.get("timestamp")) / MillisInSecond;
+
+    parsedJob.duration = lastEventTimestamp - parsedJob.starttime;
+
+    JSONObject otherinfo = (JSONObject) job.get("otherinfo");
+    if (otherinfo.get("QUERY") != null) {  // workaround for HIVE-10829
+      JSONObject query = (JSONObject) JSONValue.parse((String) otherinfo.get("QUERY"));
+
+      parsedJob.query = (String) query.get("queryText");
+      JSONObject stages = (JSONObject) ((JSONObject) query.get("queryPlan")).get("STAGE PLANS");
+
+      List<String> dagIds = new LinkedList<String>();
+      List<JSONObject> stagesList = new LinkedList<JSONObject>();
+
+      for (Object key : stages.keySet()) {
+        JSONObject stage = (JSONObject) stages.get(key);
+        if (stage.get("Tez") != null) {
+          String dagId = (String) ((JSONObject) stage.get("Tez")).get("DagId:");
+          dagIds.add(dagId);
+        }
+        stagesList.add(stage);
+      }
+      parsedJob.dagNames = dagIds;
+      parsedJob.stages = stagesList;
+    }
+
+    if (otherinfo.get("VERSION") != null) {
+      parsedJob.version = (Long) otherinfo.get("VERSION");
+    }
+    return parsedJob;
+  }
+
+  private TezVertexId parseVertex(JSONObject vertex) {
+    TezVertexId tezVertexId = new TezVertexId();
+    tezVertexId.entity = (String)vertex.get("entity");
+    JSONObject otherinfo = (JSONObject)vertex.get("otherinfo");
+    if (otherinfo != null)
+      tezVertexId.vertexName = (String)otherinfo.get("vertexName");
+    return tezVertexId;
+  }
+
+  private JSONObject getLastEvent(JSONObject atsEntity) {
+    JSONArray events = (JSONArray) atsEntity.get("events");
+    return (JSONObject) events.get(0);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSParserFactory.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSParserFactory.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSParserFactory.java
new file mode 100644
index 0000000..4ff2621
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSParserFactory.java
@@ -0,0 +1,42 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.atsJobs;
+
+import org.apache.ambari.view.ViewContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ATSParserFactory {
+
+  private ViewContext context;
+
+  public ATSParserFactory(ViewContext context) {
+    this.context = context;
+  }
+
+  public ATSParser getATSParser() {
+    ATSRequestsDelegateImpl delegate = new ATSRequestsDelegateImpl(context, getATSUrl(context));
+    return new ATSParser(delegate);
+  }
+
+  public static String getATSUrl(ViewContext context) {
+    return context.getProperties().get("yarn.ats.url");
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSRequestsDelegate.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSRequestsDelegate.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSRequestsDelegate.java
new file mode 100644
index 0000000..ac8cd22
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSRequestsDelegate.java
@@ -0,0 +1,43 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.atsJobs;
+
+import org.json.simple.JSONObject;
+
+public interface ATSRequestsDelegate {
+  String hiveQueryIdDirectUrl(String entity);
+
+  String hiveQueryIdOperationIdUrl(String operationId);
+
+  String tezDagDirectUrl(String entity);
+
+  String tezDagNameUrl(String name);
+
+  String tezVerticesListForDAGUrl(String dagId);
+
+  JSONObject hiveQueryIdList(String username);
+
+  JSONObject hiveQueryIdByOperationId(String operationId);
+
+  JSONObject tezDagByName(String name);
+
+  JSONObject tezVerticesListForDAG(String dagId);
+
+  JSONObject tezDagByEntity(String entity);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSRequestsDelegateImpl.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSRequestsDelegateImpl.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSRequestsDelegateImpl.java
new file mode 100644
index 0000000..67497fd
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/ATSRequestsDelegateImpl.java
@@ -0,0 +1,146 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.atsJobs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.commons.io.IOUtils;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+
+public class ATSRequestsDelegateImpl implements ATSRequestsDelegate {
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(ATSRequestsDelegateImpl.class);
+  public static final String EMPTY_ENTITIES_JSON = "{ \"entities\" : [  ] }";
+
+  private ViewContext context;
+  private String atsUrl;
+
+  public ATSRequestsDelegateImpl(ViewContext context, String atsUrl) {
+    this.context = context;
+    this.atsUrl = addProtocolIfMissing(atsUrl);
+  }
+
+  private String addProtocolIfMissing(String atsUrl) {
+    if (!atsUrl.matches("^[^:]+://.*$"))
+      atsUrl = "http://" + atsUrl;
+    return atsUrl;
+  }
+
+  @Override
+  public String hiveQueryIdDirectUrl(String entity) {
+    return atsUrl + "/ws/v1/timeline/HIVE_QUERY_ID/" + entity;
+  }
+
+  @Override
+  public String hiveQueryIdOperationIdUrl(String operationId) {
+    // ATS parses operationId started with digit as integer and not returns the response.
+    // Quotation prevents this.
+    return atsUrl + "/ws/v1/timeline/HIVE_QUERY_ID?primaryFilter=operationid:%22" + operationId + "%22";
+  }
+
+  @Override
+  public String tezDagDirectUrl(String entity) {
+    return atsUrl + "/ws/v1/timeline/TEZ_DAG_ID/" + entity;
+  }
+
+  @Override
+  public String tezDagNameUrl(String name) {
+    return atsUrl + "/ws/v1/timeline/TEZ_DAG_ID?primaryFilter=dagName:" + name;
+  }
+
+  @Override
+  public String tezVerticesListForDAGUrl(String dagId) {
+    return atsUrl + "/ws/v1/timeline/TEZ_VERTEX_ID?primaryFilter=TEZ_DAG_ID:" + dagId;
+  }
+
+  @Override
+  public JSONObject hiveQueryIdList(String username) {
+    String hiveQueriesListUrl = atsUrl + "/ws/v1/timeline/HIVE_QUERY_ID?primaryFilter=requestuser:" + username;
+    String response = readFromWithDefault(hiveQueriesListUrl, "{ \"entities\" : [  ] }");
+    return (JSONObject) JSONValue.parse(response);
+  }
+
+  @Override
+  public JSONObject hiveQueryIdByOperationId(String operationId) {
+    String hiveQueriesListUrl = hiveQueryIdOperationIdUrl(operationId);
+    String response = readFromWithDefault(hiveQueriesListUrl, "{ \"entities\" : [  ] }");
+    return (JSONObject) JSONValue.parse(response);
+  }
+
+  @Override
+  public JSONObject tezDagByName(String name) {
+    String tezDagUrl = tezDagNameUrl(name);
+    String response = readFromWithDefault(tezDagUrl, EMPTY_ENTITIES_JSON);
+    return (JSONObject) JSONValue.parse(response);
+  }
+
+  @Override
+  public JSONObject tezDagByEntity(String entity) {
+    String tezDagEntityUrl = tezDagEntityUrl(entity);
+    String response = readFromWithDefault(tezDagEntityUrl, EMPTY_ENTITIES_JSON);
+    return (JSONObject) JSONValue.parse(response);
+  }
+
+  private String tezDagEntityUrl(String entity) {
+    return atsUrl + "/ws/v1/timeline/TEZ_DAG_ID?primaryFilter=callerId:" + entity;
+  }
+
+  public boolean checkATSStatus() throws IOException {
+    String url = atsUrl + "/ws/v1/timeline/";
+    InputStream responseInputStream = context.getURLStreamProvider().readAsCurrent(url, "GET",
+            (String)null, new HashMap<String, String>());
+     IOUtils.toString(responseInputStream);
+    return true;
+  }
+
+  @Override
+  public JSONObject tezVerticesListForDAG(String dagId) {
+    String response = readFromWithDefault(tezVerticesListForDAGUrl(dagId), "{ \"entities\" : [  ] }");
+    return (JSONObject) JSONValue.parse(response);
+  }
+
+
+
+  protected String readFromWithDefault(String atsUrl, String defaultResponse) {
+    String response;
+    try {
+      InputStream responseInputStream = context.getURLStreamProvider().readAsCurrent(atsUrl, "GET",
+          (String)null, new HashMap<String, String>());
+      response = IOUtils.toString(responseInputStream);
+    } catch (IOException e) {
+      LOG.error("Error while reading from ATS", e);
+      response = defaultResponse;
+    }
+    return response;
+  }
+
+  public String getAtsUrl() {
+    return atsUrl;
+  }
+
+  public void setAtsUrl(String atsUrl) {
+    this.atsUrl = atsUrl;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/HiveQueryId.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/HiveQueryId.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/HiveQueryId.java
new file mode 100644
index 0000000..572749d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/HiveQueryId.java
@@ -0,0 +1,42 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.atsJobs;
+
+import org.json.simple.JSONObject;
+
+import java.util.List;
+
+public class HiveQueryId {
+  public static long ATS_15_RESPONSE_VERSION = 2; // version returned from ATS 1.5 release
+
+  public String url;
+
+  public String entity;
+  public String query;
+
+  public List<String> dagNames;
+
+  public List<JSONObject> stages;
+
+  public long starttime;
+  public long duration;
+  public String operationId;
+  public String user;
+  public long version;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/IATSParser.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/IATSParser.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/IATSParser.java
new file mode 100644
index 0000000..e545c50
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/IATSParser.java
@@ -0,0 +1,33 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.atsJobs;
+
+import java.util.List;
+
+public interface IATSParser {
+  List<HiveQueryId> getHiveQueryIdsList(String username);
+
+  List<TezVertexId> getVerticesForDAGId(String dagId);
+
+  HiveQueryId getHiveQueryIdByOperationId(String guidString);
+
+  TezDagId getTezDAGByName(String name);
+
+  TezDagId getTezDAGByEntity(String entity);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/TezDagId.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/TezDagId.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/TezDagId.java
new file mode 100644
index 0000000..80fef19
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/TezDagId.java
@@ -0,0 +1,26 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.atsJobs;
+
+public class TezDagId {
+  public static final String STATUS_UNKNOWN = "UNKNOWN";
+  public String applicationId = "";
+  public String entity = "";
+  public String status = STATUS_UNKNOWN;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/TezVertexId.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/TezVertexId.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/TezVertexId.java
new file mode 100644
index 0000000..6ba11bb
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/atsJobs/TezVertexId.java
@@ -0,0 +1,24 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.atsJobs;
+
+public class TezVertexId {
+  public String entity;
+  public String vertexName;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMParser.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMParser.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMParser.java
new file mode 100644
index 0000000..7bde8b0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMParser.java
@@ -0,0 +1,129 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.rm;
+
+import org.apache.ambari.view.hive2.resources.jobs.atsJobs.TezVertexId;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Parser of Resource Manager responses
+ */
+public class RMParser {
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(RMParser.class);
+  private RMRequestsDelegate delegate;
+
+  public RMParser(RMRequestsDelegate delegate) {
+    this.delegate = delegate;
+  }
+
+  /**
+   * Progress of DAG
+   * @param appId App Id
+   * @param dagId DAG Id
+   * @return progress of DAG
+   */
+  public Double getDAGProgress(String appId, String dagId) {
+    String dagIdx = parseDagIdIndex(dagId);
+    JSONObject progresses = delegate.dagProgress(appId, dagIdx);
+
+    double dagProgressValue;
+    if (progresses != null) {
+      JSONObject dagProgress = (JSONObject) progresses.get("dagProgress");
+      dagProgressValue = (Double) (dagProgress.get("progress"));
+    } else {
+      LOG.error("Error while retrieving progress of " + appId + ":" + dagId + ". 0 assumed.");
+      dagProgressValue = 0;
+    }
+    return dagProgressValue;
+  }
+
+  /**
+   * Progress of vertices
+   * @param appId App Id
+   * @param dagId DAG Id
+   * @param vertices vertices list
+   * @return list of vertices
+   */
+  public List<VertexProgress> getDAGVerticesProgress(String appId, String dagId, List<TezVertexId> vertices) {
+    String dagIdx = parseDagIdIndex(dagId);
+
+    Map<String, String> vertexIdToEntityMapping = new HashMap<String, String>();
+    StringBuilder builder = new StringBuilder();
+    if (vertices.size() > 0) {
+      for (TezVertexId vertexId : vertices) {
+        String[] parts = vertexId.entity.split("_");
+        String vertexIdx = parts[parts.length - 1];
+        builder.append(vertexIdx).append(",");
+
+        vertexIdToEntityMapping.put(vertexId.entity, vertexId.vertexName);
+      }
+      builder.setLength(builder.length() - 1); // remove last comma
+    }
+
+    String commaSeparatedVertices = builder.toString();
+
+    List<VertexProgress> parsedVertexProgresses = new LinkedList<VertexProgress>();
+    JSONObject vertexProgressesResponse = delegate.verticesProgress(
+        appId, dagIdx, commaSeparatedVertices);
+    if (vertexProgressesResponse == null) {
+      LOG.error("Error while retrieving progress of vertices " +
+          appId + ":" + dagId + ":" + commaSeparatedVertices + ". 0 assumed for all vertices.");
+      for (TezVertexId vertexId : vertices) {
+        VertexProgress vertexProgressInfo = new VertexProgress();
+        vertexProgressInfo.name = vertexId.vertexName;
+        vertexProgressInfo.progress = 0.0;
+        parsedVertexProgresses.add(vertexProgressInfo);
+      }
+      return parsedVertexProgresses;
+    }
+    JSONArray vertexProgresses = (JSONArray) vertexProgressesResponse.get("vertexProgresses");
+
+    for (Object vertex : vertexProgresses) {
+      JSONObject jsonObject = (JSONObject) vertex;
+
+      VertexProgress vertexProgressInfo = new VertexProgress();
+      vertexProgressInfo.id = (String) jsonObject.get("id");
+      vertexProgressInfo.name = vertexIdToEntityMapping.get(vertexProgressInfo.id);
+      vertexProgressInfo.progress = (Double) jsonObject.get("progress");
+
+      parsedVertexProgresses.add(vertexProgressInfo);
+    }
+    return parsedVertexProgresses;
+  }
+
+  public String parseDagIdIndex(String dagId) {
+    String[] dagIdParts = dagId.split("_");
+    return dagIdParts[dagIdParts.length - 1];
+  }
+
+  public static class VertexProgress {
+    public String id;
+    public String name;
+    public Double progress;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMParserFactory.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMParserFactory.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMParserFactory.java
new file mode 100644
index 0000000..4b28e64
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMParserFactory.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.jobs.rm;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.utils.ambari.AmbariApi;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RMParserFactory {
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(RMParserFactory.class);
+
+  private final ViewContext context;
+  private final AmbariApi ambariApi;
+
+  public RMParserFactory(ViewContext context) {
+    this.context = context;
+    this.ambariApi = new AmbariApi(context);
+  }
+
+  public RMParser getRMParser() {
+    String rmUrl = getRMUrl();
+
+    RMRequestsDelegate delegate = new RMRequestsDelegateImpl(context, rmUrl);
+    return new RMParser(delegate);
+  }
+
+  public String getRMUrl() {
+    return ambariApi.getServices().getRMUrl();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMRequestsDelegate.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMRequestsDelegate.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMRequestsDelegate.java
new file mode 100644
index 0000000..5c059c0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMRequestsDelegate.java
@@ -0,0 +1,31 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.rm;
+
+import org.json.simple.JSONObject;
+
+public interface RMRequestsDelegate {
+  String dagProgressUrl(String appId, String dagIdx);
+
+  String verticesProgressUrl(String appId, String dagIdx, String vertices);
+
+  JSONObject dagProgress(String appId, String dagIdx);
+
+  JSONObject verticesProgress(String appId, String dagIdx, String commaSeparatedVertices);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMRequestsDelegateImpl.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMRequestsDelegateImpl.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMRequestsDelegateImpl.java
new file mode 100644
index 0000000..6d2d22e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/rm/RMRequestsDelegateImpl.java
@@ -0,0 +1,99 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.rm;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.apache.commons.io.IOUtils;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+
+public class RMRequestsDelegateImpl implements RMRequestsDelegate {
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(RMRequestsDelegateImpl.class);
+  public static final String EMPTY_ENTITIES_JSON = "{ \"entities\" : [  ] }";
+
+  private ViewContext context;
+  private String rmUrl;
+
+  public RMRequestsDelegateImpl(ViewContext context, String rmUrl) {
+    this.context = context;
+    this.rmUrl = rmUrl;
+  }
+
+  @Override
+  public String dagProgressUrl(String appId, String dagIdx) {
+    return rmUrl + String.format("/proxy/%s/ws/v1/tez/dagProgress?dagID=%s", appId, dagIdx);
+  }
+
+  @Override
+  public String verticesProgressUrl(String appId, String dagIdx, String vertices) {
+    return rmUrl + String.format("/proxy/%s/ws/v1/tez/vertexProgresses?dagID=%s&vertexID=%s", appId, dagIdx, vertices);
+  }
+
+  @Override
+  public JSONObject dagProgress(String appId, String dagIdx) {
+    String url = dagProgressUrl(appId, dagIdx);
+    String response;
+    try {
+      InputStream responseInputStream = context.getURLStreamProvider().readFrom(url, "GET",
+          (String)null, new HashMap<String, String>());
+      response = IOUtils.toString(responseInputStream);
+    } catch (IOException e) {
+      throw new ServiceFormattedException(
+          String.format("R010 DAG %s in app %s not found or ResourceManager is unreachable", dagIdx, appId));
+    }
+    return (JSONObject) JSONValue.parse(response);
+  }
+
+  @Override
+  public JSONObject verticesProgress(String appId, String dagIdx, String commaSeparatedVertices) {
+    String url = verticesProgressUrl(appId, dagIdx, commaSeparatedVertices);
+    String response;
+    try {
+      InputStream responseInputStream = context.getURLStreamProvider().readFrom(url, "GET",
+          (String)null, new HashMap<String, String>());
+      response = IOUtils.toString(responseInputStream);
+    } catch (IOException e) {
+      throw new ServiceFormattedException(
+          String.format("R020 DAG %s in app %s not found or ResourceManager is unreachable", dagIdx, appId));
+    }
+    return (JSONObject) JSONValue.parse(response);
+  }
+
+  protected String readFromWithDefault(String url, String defaultResponse) {
+    String response;
+    try {
+      InputStream responseInputStream = context.getURLStreamProvider().readFrom(url, "GET",
+          (String)null, new HashMap<String, String>());
+      response = IOUtils.toString(responseInputStream);
+    } catch (IOException e) {
+      LOG.error("Error while reading from RM", e);
+      response = defaultResponse;
+    }
+    return response;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/IJobControllerFactory.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/IJobControllerFactory.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/IJobControllerFactory.java
new file mode 100644
index 0000000..1e1345e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/IJobControllerFactory.java
@@ -0,0 +1,23 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.viewJobs;
+
+public interface IJobControllerFactory {
+  JobController createControllerForJob(Job job);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/Job.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/Job.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/Job.java
new file mode 100644
index 0000000..816e77a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/Job.java
@@ -0,0 +1,131 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.viewJobs;
+
+
+import org.apache.ambari.view.hive2.persistence.utils.Indexed;
+import org.apache.ambari.view.hive2.persistence.utils.PersonalResource;
+
+import java.io.Serializable;
+
+/**
+ * Interface for ExecuteJob bean to create Proxy for it
+ */
+public interface Job extends Serializable,Indexed,PersonalResource {
+  String JOB_STATE_UNKNOWN = "UNKNOWN";
+  String JOB_STATE_INITIALIZED = "INITIALIZED";
+  String JOB_STATE_RUNNING = "RUNNING";
+  String JOB_STATE_FINISHED = "SUCCEEDED";
+  String JOB_STATE_CANCELED = "CANCELED";
+  String JOB_STATE_CLOSED = "CLOSED";
+  String JOB_STATE_ERROR = "ERROR";
+  String JOB_STATE_PENDING = "PENDING";
+
+  String getId();
+
+  void setId(String id);
+
+  String getOwner();
+
+  void setOwner(String owner);
+
+  String getTitle();
+
+  void setTitle(String title);
+
+  String getQueryFile();
+
+  void setQueryFile(String queryFile);
+
+  Long getDateSubmitted();
+
+  void setDateSubmitted(Long dateSubmitted);
+
+  Long getDuration();
+
+  void setDuration(Long duration);
+
+  String getStatus();
+
+  void setStatus(String status);
+
+  String getForcedContent();
+
+  void setForcedContent(String forcedContent);
+
+  String getQueryId();
+
+  void setQueryId(String queryId);
+
+  String getStatusDir();
+
+  void setStatusDir(String statusDir);
+
+  String getDataBase();
+
+  void setDataBase(String dataBase);
+
+  String getLogFile();
+
+  void setLogFile(String logFile);
+
+  String getConfFile();
+
+  void setConfFile(String confFile);
+
+  String getApplicationId();
+
+  void setApplicationId(String applicationId);
+
+  String getDagName();
+
+  void setDagName(String dagName);
+
+  String getDagId();
+
+  void setDagId(String dagId);
+
+  String getSessionTag();
+
+  void setSessionTag(String sessionTag);
+
+  String getSqlState();
+
+  void setSqlState(String sqlState);
+
+  String getStatusMessage();
+
+  void setStatusMessage(String message);
+
+  String getReferrer();
+
+  void setReferrer(String referrer);
+
+  String getGlobalSettings();
+
+  void setGlobalSettings(String globalSettings);
+
+  String getGuid();
+
+  void setGuid(String guid);
+
+  String getErrorFile();
+
+  void setErrorFile(String errorFile);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobController.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobController.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobController.java
new file mode 100644
index 0000000..46a87d9
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobController.java
@@ -0,0 +1,44 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.viewJobs;
+
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+
+public interface JobController {
+
+  void submit() throws Throwable;
+
+  void cancel() throws ItemNotFound;
+
+  Job getJob();
+
+  /**
+   * Use carefully. Returns unproxied bean object
+   * @return unproxied bean object
+   */
+  Job getJobPOJO();
+
+  void afterCreation();
+
+  void update();
+
+  boolean isModified();
+
+  void clearModified();
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobControllerFactory.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobControllerFactory.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobControllerFactory.java
new file mode 100644
index 0000000..8428a87
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobControllerFactory.java
@@ -0,0 +1,40 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.viewJobs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.utils.SharedObjectsFactory;
+
+public class JobControllerFactory implements IJobControllerFactory {
+  private SharedObjectsFactory sharedObjectsFactory;
+  private ViewContext context;
+
+  public JobControllerFactory(ViewContext context, SharedObjectsFactory sharedObjectsFactory) {
+    this.sharedObjectsFactory = sharedObjectsFactory;
+    this.context = context;
+  }
+
+  @Override
+  public JobController createControllerForJob(Job job) {
+    return new JobControllerImpl(context, job,
+        sharedObjectsFactory.getSavedQueryResourceManager(),
+        sharedObjectsFactory.getATSParser(),
+        sharedObjectsFactory.getHdfsApi());
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobControllerImpl.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobControllerImpl.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobControllerImpl.java
new file mode 100644
index 0000000..a3edc8f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobControllerImpl.java
@@ -0,0 +1,309 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.jobs.viewJobs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.client.AsyncJobRunner;
+import org.apache.ambari.view.hive2.client.AsyncJobRunnerImpl;
+import org.apache.ambari.view.hive2.client.ConnectionConfig;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.resources.jobs.ModifyNotificationDelegate;
+import org.apache.ambari.view.hive2.resources.jobs.ModifyNotificationInvocationHandler;
+import org.apache.ambari.view.hive2.resources.jobs.atsJobs.IATSParser;
+import org.apache.ambari.view.hive2.resources.savedQueries.SavedQuery;
+import org.apache.ambari.view.hive2.resources.savedQueries.SavedQueryResourceManager;
+import org.apache.ambari.view.hive2.utils.BadRequestFormattedException;
+import org.apache.ambari.view.hive2.utils.FilePaginator;
+import org.apache.ambari.view.hive2.utils.MisconfigurationFormattedException;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.apache.ambari.view.hive2.ConnectionFactory;
+import org.apache.ambari.view.hive2.ConnectionSystem;
+import org.apache.ambari.view.hive2.actor.message.AsyncJob;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.ambari.view.utils.hdfs.HdfsApiException;
+import org.apache.ambari.view.utils.hdfs.HdfsUtil;
+import org.apache.commons.lang3.ArrayUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.lang.reflect.Proxy;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class JobControllerImpl implements JobController, ModifyNotificationDelegate {
+    private final static Logger LOG =
+            LoggerFactory.getLogger(JobControllerImpl.class);
+
+    private ViewContext context;
+    private HdfsApi hdfsApi;
+    private Job jobUnproxied;
+    private Job job;
+    private boolean modified;
+
+    private SavedQueryResourceManager savedQueryResourceManager;
+    private IATSParser atsParser;
+
+    /**
+     * JobController constructor
+     * Warning: Create JobControllers ONLY using JobControllerFactory!
+     */
+    public JobControllerImpl(ViewContext context, Job job,
+                             SavedQueryResourceManager savedQueryResourceManager,
+                             IATSParser atsParser,
+                             HdfsApi hdfsApi) {
+        this.context = context;
+        setJobPOJO(job);
+        this.savedQueryResourceManager = savedQueryResourceManager;
+        this.atsParser = atsParser;
+        this.hdfsApi = hdfsApi;
+
+    }
+
+    public String getQueryForJob() {
+        FilePaginator paginator = new FilePaginator(job.getQueryFile(), hdfsApi);
+        String query;
+        try {
+            query = paginator.readPage(0);  //warning - reading only 0 page restricts size of query to 1MB
+        } catch (IOException e) {
+            throw new ServiceFormattedException("F030 Error when reading file " + job.getQueryFile(), e);
+        } catch (InterruptedException e) {
+            throw new ServiceFormattedException("F030 Error when reading file " + job.getQueryFile(), e);
+        }
+        return query;
+    }
+
+    private static final String DEFAULT_DB = "default";
+
+    public String getJobDatabase() {
+        if (job.getDataBase() != null) {
+            return job.getDataBase();
+        } else {
+            return DEFAULT_DB;
+        }
+    }
+
+
+    @Override
+    public void submit() throws Throwable {
+        String jobDatabase = getJobDatabase();
+        String query = getQueryForJob();
+        ConnectionSystem system = ConnectionSystem.getInstance();
+        AsyncJobRunner asyncJobRunner = new AsyncJobRunnerImpl(context, system.getOperationController(context), system.getActorSystem());
+        AsyncJob asyncJob = new AsyncJob(job.getId(), context.getUsername(), getStatements(jobDatabase, query), job.getLogFile(), context);
+        asyncJobRunner.submitJob(getHiveConnectionConfig(), asyncJob, job);
+
+    }
+
+    private String[] getStatements(String jobDatabase, String query) {
+      String[] queries = query.split(";");
+
+
+      String[] strings = {"use " + jobDatabase};
+      return ArrayUtils.addAll(strings, queries);
+    }
+
+
+    @Override
+    public void cancel() throws ItemNotFound {
+        //TODO: Cancel job
+    }
+
+    @Override
+    public void update() {
+        updateJobDuration();
+    }
+
+
+    @Override
+    public Job getJob() {
+        return job;
+    }
+
+    /**
+     * Use carefully. Returns unproxied bean object
+     * @return unproxied bean object
+     */
+    @Override
+    public Job getJobPOJO() {
+        return jobUnproxied;
+    }
+
+    public void setJobPOJO(Job jobPOJO) {
+        Job jobModifyNotificationProxy = (Job) Proxy.newProxyInstance(jobPOJO.getClass().getClassLoader(),
+                new Class[]{Job.class},
+                new ModifyNotificationInvocationHandler(jobPOJO, this));
+        this.job = jobModifyNotificationProxy;
+
+        this.jobUnproxied = jobPOJO;
+    }
+
+
+    @Override
+    public void afterCreation() {
+        setupStatusDirIfNotPresent();
+        setupQueryFileIfNotPresent();
+        setupLogFileIfNotPresent();
+
+        setCreationDate();
+    }
+
+    public void setupLogFileIfNotPresent() {
+        if (job.getLogFile() == null || job.getLogFile().isEmpty()) {
+            setupLogFile();
+        }
+    }
+
+    public void setupQueryFileIfNotPresent() {
+        if (job.getQueryFile() == null || job.getQueryFile().isEmpty()) {
+            setupQueryFile();
+        }
+    }
+
+    public void setupStatusDirIfNotPresent() {
+        if (job.getStatusDir() == null || job.getStatusDir().isEmpty()) {
+            setupStatusDir();
+        }
+    }
+
+    private static final long MillisInSecond = 1000L;
+
+    public void updateJobDuration() {
+        job.setDuration(System.currentTimeMillis() / MillisInSecond - job.getDateSubmitted());
+    }
+
+    public void setCreationDate() {
+        job.setDateSubmitted(System.currentTimeMillis() / MillisInSecond);
+    }
+
+
+    private void setupLogFile() {
+        LOG.debug("Creating log file for job#" + job.getId());
+
+        String logFile = job.getStatusDir() + "/" + "logs";
+        try {
+            HdfsUtil.putStringToFile(hdfsApi, logFile, "");
+        } catch (HdfsApiException e) {
+            throw new ServiceFormattedException(e);
+        }
+
+        job.setLogFile(logFile);
+        LOG.debug("Log file for job#" + job.getId() + ": " + logFile);
+    }
+
+    private void setupStatusDir() {
+        String newDirPrefix = makeStatusDirectoryPrefix();
+        String newDir = null;
+        try {
+            newDir = HdfsUtil.findUnallocatedFileName(hdfsApi, newDirPrefix, "");
+        } catch (HdfsApiException e) {
+            throw new ServiceFormattedException(e);
+        }
+
+        job.setStatusDir(newDir);
+        LOG.debug("Status dir for job#" + job.getId() + ": " + newDir);
+    }
+
+    private String makeStatusDirectoryPrefix() {
+        String userScriptsPath = context.getProperties().get("jobs.dir");
+
+        if (userScriptsPath == null) { // TODO: move check to initialization code
+            String msg = "jobs.dir is not configured!";
+            LOG.error(msg);
+            throw new MisconfigurationFormattedException("jobs.dir");
+        }
+
+        String normalizedName = String.format("hive-job-%s", job.getId());
+        String timestamp = new SimpleDateFormat("yyyy-MM-dd_hh-mm").format(new Date());
+        return String.format(userScriptsPath +
+                "/%s-%s", normalizedName, timestamp);
+    }
+
+    private void setupQueryFile() {
+        String statusDir = job.getStatusDir();
+        assert statusDir != null : "setupStatusDir() should be called first";
+
+        String jobQueryFilePath = statusDir + "/" + "query.hql";
+
+        try {
+
+            if (job.getForcedContent() != null) {
+
+                HdfsUtil.putStringToFile(hdfsApi, jobQueryFilePath, job.getForcedContent());
+                job.setForcedContent("");  // prevent forcedContent to be written to DB
+
+            } else if (job.getQueryId() != null) {
+
+                String savedQueryFile = getRelatedSavedQueryFile();
+                hdfsApi.copy(savedQueryFile, jobQueryFilePath);
+                job.setQueryFile(jobQueryFilePath);
+
+            } else {
+
+                throw new BadRequestFormattedException("queryId or forcedContent should be passed!", null);
+
+            }
+
+        } catch (IOException e) {
+            throw new ServiceFormattedException("F040 Error when creating file " + jobQueryFilePath, e);
+        } catch (InterruptedException e) {
+            throw new ServiceFormattedException("F040 Error when creating file " + jobQueryFilePath, e);
+        } catch (HdfsApiException e) {
+            throw new ServiceFormattedException(e);
+        }
+        job.setQueryFile(jobQueryFilePath);
+
+        LOG.debug("Query file for job#" + job.getId() + ": " + jobQueryFilePath);
+    }
+
+
+    private ConnectionConfig getHiveConnectionConfig() {
+        return ConnectionFactory.create(context);
+    }
+
+    private String getRelatedSavedQueryFile() {
+        SavedQuery savedQuery;
+        try {
+            savedQuery = savedQueryResourceManager.read(job.getQueryId());
+        } catch (ItemNotFound itemNotFound) {
+            throw new BadRequestFormattedException("queryId not found!", itemNotFound);
+        }
+        return savedQuery.getQueryFile();
+    }
+
+    @Override
+    public boolean onModification(Object object) {
+        setModified(true);
+        return true;
+    }
+
+    @Override
+    public boolean isModified() {
+        return modified;
+    }
+
+    public void setModified(boolean modified) {
+        this.modified = modified;
+    }
+
+    @Override
+    public void clearModified() {
+        setModified(false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobImpl.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobImpl.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobImpl.java
new file mode 100644
index 0000000..b71e2f7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobImpl.java
@@ -0,0 +1,322 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.viewJobs;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+import java.beans.Transient;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+/**
+ * Bean to represent saved query
+ */
+public class JobImpl implements Job {
+  private String title = null;
+  private String queryFile = null;
+  private String statusDir = null;
+  private Long dateSubmitted = 0L;
+  private Long duration = 0L;
+  private String forcedContent = null;
+  private String dataBase = null;
+  private String queryId = null;
+
+  private String status = JOB_STATE_UNKNOWN;
+  private String statusMessage = null;
+  private String sqlState = null;
+
+  private String applicationId;
+  private String dagId;
+  private String dagName;
+
+  private String sessionTag;
+  private String referrer;
+  private String globalSettings;
+
+  private String id = null;
+  private String owner = null;
+
+  private String logFile;
+  private String confFile;
+  private String errorFile;
+
+  private String guid = null;
+
+  public JobImpl() {}
+  public JobImpl(Map<String, Object> stringObjectMap) throws InvocationTargetException, IllegalAccessException {
+    for (Map.Entry<String, Object> entry : stringObjectMap.entrySet())  {
+      try {
+        PropertyUtils.setProperty(this, entry.getKey(), entry.getValue());
+      } catch (NoSuchMethodException e) {
+        //do nothing, skip
+      }
+    }
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (!(o instanceof Job)) return false;
+
+    JobImpl job = (JobImpl) o;
+
+    if (id != null ? !id.equals(job.id) : job.id != null) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    return id != null ? id.hashCode() : 0;
+  }
+
+  @Override
+  public String getId() {
+    return id;
+  }
+
+  @Override
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  @Override
+  public String getOwner() {
+    return owner;
+  }
+
+  @Override
+  public void setOwner(String owner) {
+    this.owner = owner;
+  }
+
+  @Override
+  public String getTitle() {
+    return title;
+  }
+
+  @Override
+  public void setTitle(String title) {
+    this.title = title;
+  }
+
+  @Override
+  public String getQueryFile() {
+    return queryFile;
+  }
+
+  @Override
+  public void setQueryFile(String queryFile) {
+    this.queryFile = queryFile;
+  }
+
+  @Override
+  public Long getDateSubmitted() {
+    return dateSubmitted;
+  }
+
+  @Override
+  public void setDateSubmitted(Long dateSubmitted) {
+    this.dateSubmitted = dateSubmitted;
+  }
+
+  @Override
+  public Long getDuration() {
+    return duration;
+  }
+
+  @Override
+  public void setDuration(Long duration) {
+    this.duration = duration;
+  }
+
+  @Override
+  public String getStatus() {
+    return status;
+  }
+
+  @Override
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+  @Override
+  @Transient
+  public String getForcedContent() {
+    return forcedContent;
+  }
+
+  @Override
+  @Transient
+  public void setForcedContent(String forcedContent) {
+    this.forcedContent = forcedContent;
+  }
+
+  @Override
+  public String getQueryId() {
+    return queryId;
+  }
+
+  @Override
+  public void setQueryId(String queryId) {
+    this.queryId = queryId;
+  }
+
+  @Override
+  public String getStatusDir() {
+    return statusDir;
+  }
+
+  @Override
+  public void setStatusDir(String statusDir) {
+    this.statusDir = statusDir;
+  }
+
+  @Override
+  public String getDataBase() {
+    return dataBase;
+  }
+
+  @Override
+  public void setDataBase(String dataBase) {
+    this.dataBase = dataBase;
+  }
+
+  @Override
+  public String getLogFile() {
+    return logFile;
+  }
+
+  @Override
+  public void setLogFile(String logFile) {
+    this.logFile = logFile;
+  }
+
+  @Override
+  public String getConfFile() {
+    return confFile;
+  }
+
+  @Override
+  public void setConfFile(String confFile) {
+    this.confFile = confFile;
+  }
+
+  @Override
+  public String getApplicationId() {
+    return applicationId;
+  }
+
+  @Override
+  public void setApplicationId(String applicationId) {
+    this.applicationId = applicationId;
+  }
+
+  @Override
+  public String getDagName() {
+    return dagName;
+  }
+
+  @Override
+  public void setDagName(String dagName) {
+    this.dagName = dagName;
+  }
+
+  @Override
+  public String getDagId() {
+    return dagId;
+  }
+
+  @Override
+  public void setDagId(String dagId) {
+    this.dagId = dagId;
+  }
+
+  @Override
+  public String getSessionTag() {
+    return sessionTag;
+  }
+
+  @Override
+  public void setSessionTag(String sessionTag) {
+    this.sessionTag = sessionTag;
+  }
+
+  @Override
+  @Transient
+  public String getStatusMessage() {
+    return statusMessage;
+  }
+
+  @Override
+  @Transient
+  public void setStatusMessage(String statusMessage) {
+    this.statusMessage = statusMessage;
+  }
+
+  @Override
+  public String getSqlState() {
+    return sqlState;
+  }
+
+  @Override
+  public void setSqlState(String sqlState) {
+    this.sqlState = sqlState;
+  }
+
+  @Override
+  public String getReferrer() {
+    return referrer;
+  }
+
+  @Override
+  public void setReferrer(String referrer) {
+    this.referrer = referrer;
+  }
+
+  @Override
+  public String getGlobalSettings() {
+    return globalSettings;
+  }
+
+  @Override
+  public void setGlobalSettings(String globalSettings) {
+    this.globalSettings = globalSettings;
+  }
+
+  @Override
+  public String getGuid() {
+    return guid;
+  }
+
+  @Override
+  public void setGuid(String guid) {
+    this.guid = guid;
+  }
+
+  @Override
+  public String getErrorFile() {
+    return errorFile;
+  }
+
+  @Override
+  public void setErrorFile(String errorFile) {
+    this.errorFile = errorFile;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobResourceManager.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobResourceManager.java
new file mode 100644
index 0000000..f91363f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/viewJobs/JobResourceManager.java
@@ -0,0 +1,108 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs.viewJobs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.resources.PersonalCRUDResourceManager;
+import org.apache.ambari.view.hive2.utils.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+/**
+ * Object that provides CRUD operations for job objects
+ */
+public class JobResourceManager extends PersonalCRUDResourceManager<Job> {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(JobResourceManager.class);
+
+  private IJobControllerFactory jobControllerFactory;
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public JobResourceManager(SharedObjectsFactory sharedObjectsFactory, ViewContext context) {
+    super(JobImpl.class, sharedObjectsFactory, context);
+    jobControllerFactory = sharedObjectsFactory.getJobControllerFactory();
+  }
+
+  @Override
+  public Job create(Job object) {
+    super.create(object);
+    JobController jobController = jobControllerFactory.createControllerForJob(object);
+
+    try {
+
+      jobController.afterCreation();
+      saveIfModified(jobController);
+
+    } catch (ServiceFormattedException e) {
+      cleanupAfterErrorAndThrowAgain(object, e);
+    }
+
+    return object;
+  }
+
+  public void saveIfModified(JobController jobController) {
+    if (jobController.isModified()) {
+      save(jobController.getJobPOJO());
+      jobController.clearModified();
+    }
+  }
+
+
+  @Override
+  public Job read(Object id) throws ItemNotFound {
+    Job job = super.read(id);
+    JobController jobController =  jobControllerFactory.createControllerForJob(job);
+    jobController.update();
+    saveIfModified(jobController);
+    return job;
+  }
+
+  @Override
+  public List<Job> readAll(FilteringStrategy filteringStrategy) {
+    return super.readAll(filteringStrategy);
+  }
+
+  @Override
+  public void delete(Object resourceId) throws ItemNotFound {
+    super.delete(resourceId);
+  }
+
+  public JobController readController(Object id) throws ItemNotFound {
+    Job job = read(id);
+    return jobControllerFactory.createControllerForJob(job);
+  }
+
+  /*public Cursor getJobResultsCursor(ExecuteJob job) {
+    try {
+      JobController jobController = jobControllerFactory.createControllerForJob(job);
+      return jobController.getResults();
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException("ExecuteJob results are expired", null);
+    }
+  }*/
+
+  //TODO: New implementation
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceItem.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceItem.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceItem.java
new file mode 100644
index 0000000..ed984e4
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceItem.java
@@ -0,0 +1,78 @@
+/**
+ * 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.ambari.view.hive2.resources.resources;
+
+import org.apache.ambari.view.hive2.persistence.utils.PersonalResource;
+import org.apache.commons.beanutils.BeanUtils;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+/**
+ * Bean to represent file resource
+ */
+public class FileResourceItem implements Serializable, PersonalResource {
+  private String name;
+  private String path;
+
+  private String id;
+  private String owner;
+
+  public FileResourceItem() {}
+  public FileResourceItem(Map<String, Object> stringObjectMap) throws InvocationTargetException, IllegalAccessException {
+    BeanUtils.populate(this, stringObjectMap);
+  }
+
+  @Override
+  public String getId() {
+    return id;
+  }
+
+  @Override
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  @Override
+  public String getOwner() {
+    return owner;
+  }
+
+  @Override
+  public void setOwner(String owner) {
+    this.owner = owner;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getPath() {
+    return path;
+  }
+
+  public void setPath(String path) {
+    this.path = path;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceResourceManager.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceResourceManager.java
new file mode 100644
index 0000000..a4ea1f6
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceResourceManager.java
@@ -0,0 +1,65 @@
+/**
+ * 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.ambari.view.hive2.resources.resources;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.IStorageFactory;
+import org.apache.ambari.view.hive2.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.resources.PersonalCRUDResourceManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Object that provides CRUD operations for resource objects
+ */
+public class FileResourceResourceManager extends PersonalCRUDResourceManager<FileResourceItem> {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(FileResourceResourceManager.class);
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public FileResourceResourceManager(IStorageFactory storageFactory, ViewContext context) {
+    super(FileResourceItem.class, storageFactory, context);
+  }
+
+  @Override
+  public FileResourceItem create(FileResourceItem object) {
+    return super.create(object);
+  }
+
+  @Override
+  public FileResourceItem read(Object id) throws ItemNotFound {
+    return super.read(id);
+  }
+
+  @Override
+  public void delete(Object resourceId) throws ItemNotFound {
+    super.delete(resourceId);
+  }
+
+  @Override
+  public List<FileResourceItem> readAll(FilteringStrategy filteringStrategy) {
+    return super.readAll(filteringStrategy);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceResourceProvider.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceResourceProvider.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceResourceProvider.java
new file mode 100644
index 0000000..9e7c00a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceResourceProvider.java
@@ -0,0 +1,110 @@
+/**
+ * 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.ambari.view.hive2.resources.resources;
+
+import org.apache.ambari.view.*;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive2.utils.SharedObjectsFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Resource provider for resource
+ */
+public class FileResourceResourceProvider implements ResourceProvider<FileResourceItem> {
+  @Inject
+  ViewContext context;
+
+  protected FileResourceResourceManager resourceManager = null;
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(FileResourceResourceProvider.class);
+
+  protected synchronized FileResourceResourceManager getResourceManager() {
+    if (resourceManager == null) {
+      resourceManager = new FileResourceResourceManager(new SharedObjectsFactory(context), context);
+    }
+    return resourceManager;
+  }
+
+  @Override
+  public FileResourceItem getResource(String resourceId, Set<String> properties) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      return getResourceManager().read(resourceId);
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+  }
+
+  @Override
+  public Set<FileResourceItem> getResources(ReadRequest readRequest) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    if (context == null) {
+      return new HashSet<FileResourceItem>();
+    }
+    return new HashSet<FileResourceItem>(getResourceManager().readAll(
+        new OnlyOwnersFilteringStrategy(this.context.getUsername())));
+  }
+
+  @Override
+  public void createResource(String s, Map<String, Object> stringObjectMap) throws SystemException, ResourceAlreadyExistsException, NoSuchResourceException, UnsupportedPropertyException {
+    FileResourceItem item = null;
+    try {
+      item = new FileResourceItem(stringObjectMap);
+    } catch (InvocationTargetException e) {
+      throw new SystemException("error on creating resource", e);
+    } catch (IllegalAccessException e) {
+      throw new SystemException("error on creating resource", e);
+    }
+    getResourceManager().create(item);
+  }
+
+  @Override
+  public boolean updateResource(String resourceId, Map<String, Object> stringObjectMap) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    FileResourceItem item = null;
+    try {
+      item = new FileResourceItem(stringObjectMap);
+    } catch (InvocationTargetException e) {
+      throw new SystemException("error on updating resource", e);
+    } catch (IllegalAccessException e) {
+      throw new SystemException("error on updating resource", e);
+    }
+    try {
+      getResourceManager().update(item, resourceId);
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+
+  @Override
+  public boolean deleteResource(String resourceId) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      getResourceManager().delete(resourceId);
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceService.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceService.java
new file mode 100644
index 0000000..2ce74c3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/resources/FileResourceService.java
@@ -0,0 +1,180 @@
+/**
+ * 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.ambari.view.hive2.resources.resources;
+
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive2.BaseService;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive2.utils.NotFoundFormattedException;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.List;
+
+/**
+ * Servlet for Resources
+ * API:
+ * GET /:id
+ *      read resource
+ * POST /
+ *      create new resource
+ * GET /
+ *      get all resource of current user
+ */
+public class FileResourceService extends BaseService {
+  @Inject
+  ViewResourceHandler handler;
+
+  protected FileResourceResourceManager resourceManager = null;
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(FileResourceService.class);
+
+  protected synchronized FileResourceResourceManager getResourceManager() {
+    if (resourceManager == null) {
+      resourceManager = new FileResourceResourceManager(getSharedObjectsFactory(), context);
+    }
+    return resourceManager;
+  }
+
+  /**
+   * Get single item
+   */
+  @GET
+  @Path("{id}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getOne(@PathParam("id") String id) {
+    try {
+      FileResourceItem fileResourceItem = getResourceManager().read(id);
+      JSONObject object = new JSONObject();
+      object.put("fileResource", fileResourceItem);
+      return Response.ok(object).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Delete single item
+   */
+  @DELETE
+  @Path("{id}")
+  public Response delete(@PathParam("id") String id) {
+    try {
+      getResourceManager().delete(id);
+      return Response.status(204).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Get all resources
+   */
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getList() {
+    try {
+      LOG.debug("Getting all resources");
+      List items = getResourceManager().readAll(
+          new OnlyOwnersFilteringStrategy(this.context.getUsername()));  //TODO: move strategy to PersonalCRUDRM
+
+      JSONObject object = new JSONObject();
+      object.put("fileResources", items);
+      return Response.ok(object).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Update item
+   */
+  @PUT
+  @Path("{id}")
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response update(ResourceRequest request,
+                         @PathParam("id") String id) {
+    try {
+      getResourceManager().update(request.fileResource, id);
+      return Response.status(204).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Create resource
+   */
+  @POST
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response create(ResourceRequest request, @Context HttpServletResponse response,
+                         @Context UriInfo ui) {
+    try {
+      getResourceManager().create(request.fileResource);
+
+      FileResourceItem item = null;
+
+      item = getResourceManager().read(request.fileResource.getId());
+
+      response.setHeader("Location",
+          String.format("%s/%s", ui.getAbsolutePath().toString(), request.fileResource.getId()));
+
+      JSONObject object = new JSONObject();
+      object.put("fileResource", item);
+      return Response.ok(object).status(201).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Wrapper object for json mapping
+   */
+  public static class ResourceRequest {
+    public FileResourceItem fileResource;
+  }
+}


[14/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQuery.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQuery.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQuery.java
new file mode 100644
index 0000000..f52cde3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQuery.java
@@ -0,0 +1,96 @@
+/**
+ * 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.ambari.view.hive2.resources.savedQueries;
+
+import org.apache.ambari.view.hive2.persistence.utils.PersonalResource;
+import org.apache.commons.beanutils.BeanUtils;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+/**
+ * Bean to represent saved query
+ */
+public class SavedQuery implements Serializable, PersonalResource {
+  private String queryFile;
+  private String dataBase;
+  private String title;
+  private String shortQuery;
+
+  private String id;
+  private String owner;
+
+  public SavedQuery() {}
+  public SavedQuery(Map<String, Object> stringObjectMap) throws InvocationTargetException, IllegalAccessException {
+    BeanUtils.populate(this, stringObjectMap);
+  }
+
+  @Override
+  public String getId() {
+    return id;
+  }
+
+  @Override
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  @Override
+  public String getOwner() {
+    return owner;
+  }
+
+  @Override
+  public void setOwner(String owner) {
+    this.owner = owner;
+  }
+
+  public String getQueryFile() {
+    return queryFile;
+  }
+
+  public void setQueryFile(String queryFile) {
+    this.queryFile = queryFile;
+  }
+
+  public String getDataBase() {
+    return dataBase;
+  }
+
+  public void setDataBase(String dataBase) {
+    this.dataBase = dataBase;
+  }
+
+  public String getTitle() {
+    return title;
+  }
+
+  public void setTitle(String title) {
+    this.title = title;
+  }
+
+  public String getShortQuery() {
+    return shortQuery;
+  }
+
+  public void setShortQuery(String shortQuery) {
+    this.shortQuery = shortQuery;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQueryResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQueryResourceManager.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQueryResourceManager.java
new file mode 100644
index 0000000..ff8632f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQueryResourceManager.java
@@ -0,0 +1,162 @@
+/**
+ * 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.ambari.view.hive2.resources.savedQueries;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.resources.PersonalCRUDResourceManager;
+import org.apache.ambari.view.hive2.utils.*;
+import org.apache.ambari.view.utils.hdfs.HdfsApiException;
+import org.apache.ambari.view.utils.hdfs.HdfsUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Object that provides CRUD operations for query objects
+ */
+public class SavedQueryResourceManager extends PersonalCRUDResourceManager<SavedQuery> {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(SavedQueryResourceManager.class);
+
+  private SharedObjectsFactory sharedObjectsFactory;
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public SavedQueryResourceManager(ViewContext context, SharedObjectsFactory sharedObjectsFactory) {
+    super(SavedQuery.class, sharedObjectsFactory, context);
+    this.sharedObjectsFactory = sharedObjectsFactory;
+  }
+
+  @Override
+  public SavedQuery create(SavedQuery object) {
+    object = super.create(object);
+    try {
+
+      if (object.getQueryFile() == null || object.getQueryFile().isEmpty()) {
+        createDefaultQueryFile(object);
+      }
+
+    } catch (ServiceFormattedException e) {
+      cleanupAfterErrorAndThrowAgain(object, e);
+    }
+    return object;
+  }
+
+  private void createDefaultQueryFile(SavedQuery object) {
+    String userScriptsPath = context.getProperties().get("scripts.dir");
+    if (userScriptsPath == null) {
+      String msg = "scripts.dir is not configured!";
+      LOG.error(msg);
+      throw new MisconfigurationFormattedException("scripts.dir");
+    }
+
+    String normalizedName = String.format("hive-query-%s", object.getId());
+    String timestamp = new SimpleDateFormat("yyyy-MM-dd_hh-mm").format(new Date());
+    String baseFileName = String.format(userScriptsPath +
+        "/%s-%s", normalizedName, timestamp);
+
+    String newFilePath = null;
+    try {
+      newFilePath = HdfsUtil.findUnallocatedFileName(sharedObjectsFactory.getHdfsApi(), baseFileName, ".hql");
+      HdfsUtil.putStringToFile(sharedObjectsFactory.getHdfsApi(), newFilePath, "");
+    } catch (HdfsApiException e) {
+      throw new ServiceFormattedException(e);
+    }
+
+    object.setQueryFile(newFilePath);
+    storageFactory.getStorage().store(SavedQuery.class, object);
+  }
+
+  @Override
+  public SavedQuery read(Object id) throws ItemNotFound {
+    SavedQuery savedQuery = super.read(id);
+    fillShortQueryField(savedQuery);
+    return savedQuery;
+  }
+
+  private void fillShortQueryField(SavedQuery savedQuery) {
+    if (savedQuery.getQueryFile() != null) {
+      FilePaginator paginator = new FilePaginator(savedQuery.getQueryFile(), sharedObjectsFactory.getHdfsApi());
+      String query = null;
+      try {
+        query = paginator.readPage(0);
+      } catch (IOException e) {
+        LOG.error("Can't read query file " + savedQuery.getQueryFile());
+        return;
+      } catch (InterruptedException e) {
+        LOG.error("Can't read query file " + savedQuery.getQueryFile());
+        return;
+      }
+      savedQuery.setShortQuery(makeShortQuery(query));
+    }
+    storageFactory.getStorage().store(SavedQuery.class, savedQuery);
+  }
+
+  private void emptyShortQueryField(SavedQuery query) {
+    query.setShortQuery("");
+    storageFactory.getStorage().store(SavedQuery.class, query);
+  }
+
+  /**
+   * Generate short preview of query.
+   * Remove SET settings like "set hive.execution.engine=tez;" from beginning
+   * and trim to 42 symbols.
+   * @param query full query
+   * @return shortened query
+   */
+  protected static String makeShortQuery(String query) {
+    query = query.replaceAll("(?i)set\\s+[\\w\\-.]+(\\s*)=(\\s*)[\\w\\-.]+(\\s*);", "");
+    query = query.trim();
+    return query.substring(0, (query.length() > 42)?42:query.length());
+  }
+
+  @Override
+  public SavedQuery update(SavedQuery newObject, String id) throws ItemNotFound {
+    SavedQuery savedQuery = super.update(newObject, id);
+    // Emptying short query so that in next read, this gets updated with proper value
+    // from the queryFile
+    emptyShortQueryField(savedQuery);
+    return savedQuery;
+  }
+
+  @Override
+  public List<SavedQuery> readAll(FilteringStrategy filteringStrategy) {
+    List<SavedQuery> queries = super.readAll(filteringStrategy);
+    for(SavedQuery query : queries) {
+      String shortQuery = query.getShortQuery();
+      if(shortQuery == null || shortQuery.isEmpty()) {
+        fillShortQueryField(query);
+      }
+    }
+    return queries;
+  }
+
+  @Override
+  public void delete(Object resourceId) throws ItemNotFound {
+    super.delete(resourceId);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQueryResourceProvider.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQueryResourceProvider.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQueryResourceProvider.java
new file mode 100644
index 0000000..87f3321
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQueryResourceProvider.java
@@ -0,0 +1,113 @@
+/**
+ * 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.ambari.view.hive2.resources.savedQueries;
+
+import org.apache.ambari.view.*;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive2.utils.SharedObjectsFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Resource provider for SavedQuery
+ */
+public class SavedQueryResourceProvider implements ResourceProvider<SavedQuery> {
+  @Inject
+  ViewContext context;
+
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(SavedQueryResourceProvider.class);
+  private SharedObjectsFactory sharedObjectsFactory;
+
+  public SharedObjectsFactory getSharedObjectsFactory() {
+    if (sharedObjectsFactory == null)
+      sharedObjectsFactory = new SharedObjectsFactory(context);
+    return sharedObjectsFactory;
+  }
+
+  protected synchronized SavedQueryResourceManager getResourceManager() {
+    return getSharedObjectsFactory().getSavedQueryResourceManager();
+  }
+
+  @Override
+  public SavedQuery getResource(String resourceId, Set<String> properties) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      return getResourceManager().read(resourceId);
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+  }
+
+  @Override
+  public Set<SavedQuery> getResources(ReadRequest readRequest) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    if (context == null) {
+      return new HashSet<SavedQuery>();
+    }
+    return new HashSet<SavedQuery>(getResourceManager().readAll(
+        new OnlyOwnersFilteringStrategy(this.context.getUsername())));
+  }
+
+  @Override
+  public void createResource(String s, Map<String, Object> stringObjectMap) throws SystemException, ResourceAlreadyExistsException, NoSuchResourceException, UnsupportedPropertyException {
+    SavedQuery item = null;
+    try {
+      item = new SavedQuery(stringObjectMap);
+    } catch (InvocationTargetException e) {
+      throw new SystemException("error on creating resource", e);
+    } catch (IllegalAccessException e) {
+      throw new SystemException("error on creating resource", e);
+    }
+    getResourceManager().create(item);
+  }
+
+  @Override
+  public boolean updateResource(String resourceId, Map<String, Object> stringObjectMap) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    SavedQuery item = null;
+    try {
+      item = new SavedQuery(stringObjectMap);
+    } catch (InvocationTargetException e) {
+      throw new SystemException("error on updating resource", e);
+    } catch (IllegalAccessException e) {
+      throw new SystemException("error on updating resource", e);
+    }
+    try {
+      getResourceManager().update(item, resourceId);
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+
+  @Override
+  public boolean deleteResource(String resourceId) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      getResourceManager().delete(resourceId);
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQueryService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQueryService.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQueryService.java
new file mode 100644
index 0000000..ccc4512
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/savedQueries/SavedQueryService.java
@@ -0,0 +1,230 @@
+/**
+ * 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.ambari.view.hive2.resources.savedQueries;
+
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive2.BaseService;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive2.utils.NotFoundFormattedException;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.ambari.view.utils.hdfs.HdfsUtil;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.List;
+
+/**
+ * Servlet for queries
+ * API:
+ * GET /:id
+ *      read SavedQuery
+ * POST /
+ *      create new SavedQuery
+ *      Required: title, queryFile
+ * GET /
+ *      get all SavedQueries of current user
+ */
+public class SavedQueryService extends BaseService {
+  @Inject
+  ViewResourceHandler handler;
+
+  protected SavedQueryResourceManager resourceManager = null;
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(SavedQueryService.class);
+
+  protected synchronized SavedQueryResourceManager getResourceManager() {
+    return getSharedObjectsFactory().getSavedQueryResourceManager();
+  }
+
+  protected void setResourceManager(SavedQueryResourceManager resourceManager) {
+    this.resourceManager = resourceManager;
+  }
+
+  /**
+   * Get single item
+   */
+  @GET
+  @Path("{queryId}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getOne(@PathParam("queryId") String queryId) {
+    try {
+      SavedQuery savedQuery = getResourceManager().read(queryId);
+      JSONObject object = new JSONObject();
+      object.put("savedQuery", savedQuery);
+      return Response.ok(object).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Delete single item
+   */
+  @DELETE
+  @Path("{queryId}")
+  public Response delete(@PathParam("queryId") String queryId) {
+    try {
+      getResourceManager().delete(queryId);
+      return Response.status(204).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Get all SavedQueries
+   */
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getList() {
+    try {
+      LOG.debug("Getting all SavedQuery");
+      List allSavedQueries = getResourceManager().readAll(
+          new OnlyOwnersFilteringStrategy(this.context.getUsername()));  //TODO: move strategy to PersonalCRUDRM
+
+      JSONObject object = new JSONObject();
+      object.put("savedQueries", allSavedQueries);
+      return Response.ok(object).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Update item
+   */
+  @PUT
+  @Path("{queryId}")
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response update(SavedQueryRequest request,
+                         @PathParam("queryId") String queryId) {
+    try {
+      getResourceManager().update(request.savedQuery, queryId);
+      return Response.status(204).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Create savedQuery
+   */
+  @POST
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response create(SavedQueryRequest request, @Context HttpServletResponse response,
+                         @Context UriInfo ui) {
+    try {
+      getResourceManager().create(request.savedQuery);
+
+      SavedQuery item = null;
+
+      item = getResourceManager().read(request.savedQuery.getId());
+
+      response.setHeader("Location",
+          String.format("%s/%s", ui.getAbsolutePath().toString(), request.savedQuery.getId()));
+
+      JSONObject object = new JSONObject();
+      object.put("savedQuery", item);
+      return Response.ok(object).status(201).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Get default settings for query
+   */
+  @GET
+  @Path("defaultSettings")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getDefaultSettings() {
+    try {
+      String defaultsFile = context.getProperties().get("scripts.settings.defaults-file");
+      HdfsApi hdfsApi = getSharedObjectsFactory().getHdfsApi();
+
+      String defaults = "{\"settings\": {}}";
+      if (hdfsApi.exists(defaultsFile)) {
+        defaults = HdfsUtil.readFile(hdfsApi, defaultsFile);
+      }
+      return Response.ok(JSONValue.parse(defaults)).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Set default settings for query (overwrites if present)
+   */
+  @POST
+  @Path("defaultSettings")
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response setDefaultSettings(JSONObject settings) {
+    try {
+      String defaultsFile = context.getProperties().get("scripts.settings.defaults-file");
+      HdfsApi hdfsApi = getSharedObjectsFactory().getHdfsApi();
+
+      HdfsUtil.putStringToFile(hdfsApi, defaultsFile,
+          settings.toString());
+      String defaults = HdfsUtil.readFile(hdfsApi, defaultsFile);
+      return Response.ok(JSONValue.parse(defaults)).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Wrapper object for json mapping
+   */
+  public static class SavedQueryRequest {
+    public SavedQuery savedQuery;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDF.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDF.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDF.java
new file mode 100644
index 0000000..aa863a6
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDF.java
@@ -0,0 +1,87 @@
+/**
+ * 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.ambari.view.hive2.resources.udfs;
+
+import org.apache.ambari.view.hive2.persistence.utils.PersonalResource;
+import org.apache.commons.beanutils.BeanUtils;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+/**
+ * Bean to represent UDF
+ */
+public class UDF implements Serializable, PersonalResource {
+  private String name;
+  private String classname;
+  private String fileResource;
+
+  private String id;
+  private String owner;
+
+  public UDF() {}
+  public UDF(Map<String, Object> stringObjectMap) throws InvocationTargetException, IllegalAccessException {
+    BeanUtils.populate(this, stringObjectMap);
+  }
+
+  @Override
+  public String getId() {
+    return id;
+  }
+
+  @Override
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  @Override
+  public String getOwner() {
+    return owner;
+  }
+
+  @Override
+  public void setOwner(String owner) {
+    this.owner = owner;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getClassname() {
+    return classname;
+  }
+
+  public void setClassname(String classname) {
+    this.classname = classname;
+  }
+
+  public String getFileResource() {
+    return fileResource;
+  }
+
+  public void setFileResource(String fileResource) {
+    this.fileResource = fileResource;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDFResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDFResourceManager.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDFResourceManager.java
new file mode 100644
index 0000000..9be6c15
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDFResourceManager.java
@@ -0,0 +1,65 @@
+/**
+ * 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.ambari.view.hive2.resources.udfs;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.IStorageFactory;
+import org.apache.ambari.view.hive2.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.resources.PersonalCRUDResourceManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Object that provides CRUD operations for udf objects
+ */
+public class UDFResourceManager extends PersonalCRUDResourceManager<UDF> {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(UDFResourceManager.class);
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public UDFResourceManager(IStorageFactory storageFactory, ViewContext context) {
+    super(UDF.class, storageFactory, context);
+  }
+
+  @Override
+  public UDF read(Object id) throws ItemNotFound {
+    return super.read(id);
+  }
+
+  @Override
+  public List<UDF> readAll(FilteringStrategy filteringStrategy) {
+    return super.readAll(filteringStrategy);
+  }
+
+  @Override
+  public UDF create(UDF object) {
+    return super.create(object);
+  }
+
+  @Override
+  public void delete(Object resourceId) throws ItemNotFound {
+    super.delete(resourceId);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDFResourceProvider.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDFResourceProvider.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDFResourceProvider.java
new file mode 100644
index 0000000..1b18a14
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDFResourceProvider.java
@@ -0,0 +1,111 @@
+/**
+ * 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.ambari.view.hive2.resources.udfs;
+
+import org.apache.ambari.view.*;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive2.utils.SharedObjectsFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Resource provider for udf
+ */
+public class UDFResourceProvider implements ResourceProvider<UDF> {
+  @Inject
+  ViewContext context;
+
+  protected UDFResourceManager resourceManager = null;
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(UDFResourceProvider.class);
+
+
+  protected synchronized UDFResourceManager getResourceManager() {
+    if (resourceManager == null) {
+      resourceManager = new UDFResourceManager(new SharedObjectsFactory(context), context);
+    }
+    return resourceManager;
+  }
+
+  @Override
+  public UDF getResource(String resourceId, Set<String> properties) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      return getResourceManager().read(resourceId);
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+  }
+
+  @Override
+  public Set<UDF> getResources(ReadRequest readRequest) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    if (context == null) {
+      return new HashSet<UDF>();
+    }
+    return new HashSet<UDF>(getResourceManager().readAll(
+        new OnlyOwnersFilteringStrategy(this.context.getUsername())));
+  }
+
+  @Override
+  public void createResource(String s, Map<String, Object> stringObjectMap) throws SystemException, ResourceAlreadyExistsException, NoSuchResourceException, UnsupportedPropertyException {
+    UDF item = null;
+    try {
+      item = new UDF(stringObjectMap);
+    } catch (InvocationTargetException e) {
+      throw new SystemException("error on creating resource", e);
+    } catch (IllegalAccessException e) {
+      throw new SystemException("error on creating resource", e);
+    }
+    getResourceManager().create(item);
+  }
+
+  @Override
+  public boolean updateResource(String resourceId, Map<String, Object> stringObjectMap) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    UDF item = null;
+    try {
+      item = new UDF(stringObjectMap);
+    } catch (InvocationTargetException e) {
+      throw new SystemException("error on updating resource", e);
+    } catch (IllegalAccessException e) {
+      throw new SystemException("error on updating resource", e);
+    }
+    try {
+      getResourceManager().update(item, resourceId);
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+
+  @Override
+  public boolean deleteResource(String resourceId) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      getResourceManager().delete(resourceId);
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDFService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDFService.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDFService.java
new file mode 100644
index 0000000..4fad828
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/udfs/UDFService.java
@@ -0,0 +1,193 @@
+/**
+ * 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.ambari.view.hive2.resources.udfs;
+
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive2.BaseService;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive2.resources.resources.FileResourceResourceManager;
+import org.apache.ambari.view.hive2.utils.NotFoundFormattedException;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.List;
+
+/**
+ * Servlet for UDFs
+ * API:
+ * GET /:id
+ *      read udf
+ * POST /
+ *      create new udf
+ * GET /
+ *      get all udf of current user
+ */
+public class UDFService extends BaseService {
+  @Inject
+  ViewResourceHandler handler;
+
+  protected UDFResourceManager resourceManager = null;
+  protected FileResourceResourceManager fileResourceResourceManager = null;
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(UDFService.class);
+
+  protected synchronized UDFResourceManager getResourceManager() {
+    if (resourceManager == null) {
+      resourceManager = new UDFResourceManager(getSharedObjectsFactory(), context);
+    }
+    return resourceManager;
+  }
+
+  protected synchronized FileResourceResourceManager getFileResourceResourceManager() {
+    if (fileResourceResourceManager == null) {
+      fileResourceResourceManager = new FileResourceResourceManager(getSharedObjectsFactory(), context);
+    }
+    return fileResourceResourceManager;
+  }
+
+  /**
+   * Get single item
+   */
+  @GET
+  @Path("{id}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getOne(@PathParam("id") String id) {
+    try {
+      UDF udf = getResourceManager().read(id);
+      JSONObject object = new JSONObject();
+      object.put("udf", udf);
+      return Response.ok(object).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Delete single item
+   */
+  @DELETE
+  @Path("{id}")
+  public Response delete(@PathParam("id") String id) {
+    try {
+      getResourceManager().delete(id);
+      return Response.status(204).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Get all UDFs
+   */
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getList() {
+    try {
+      LOG.debug("Getting all udf");
+      List items = getResourceManager().readAll(
+          new OnlyOwnersFilteringStrategy(this.context.getUsername()));  //TODO: move strategy to PersonalCRUDRM
+
+      JSONObject object = new JSONObject();
+      object.put("udfs", items);
+      return Response.ok(object).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Update item
+   */
+  @PUT
+  @Path("{id}")
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response update(UDFRequest request,
+                         @PathParam("id") String id) {
+    try {
+      if (request.udf.getFileResource() != null)
+        getFileResourceResourceManager().read(request.udf.getFileResource());
+      getResourceManager().update(request.udf, id);
+      return Response.status(204).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Create udf
+   */
+  @POST
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response create(UDFRequest request, @Context HttpServletResponse response,
+                         @Context UriInfo ui) {
+    try {
+      if (request.udf.getFileResource() != null)
+        getFileResourceResourceManager().read(request.udf.getFileResource());
+      getResourceManager().create(request.udf);
+
+      UDF item = null;
+
+      item = getResourceManager().read(request.udf.getId());
+
+      response.setHeader("Location",
+          String.format("%s/%s", ui.getAbsolutePath().toString(), request.udf.getId()));
+
+      JSONObject object = new JSONObject();
+      object.put("udf", item);
+      return Response.ok(object).status(201).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Wrapper object for json mapping
+   */
+  public static class UDFRequest {
+    public UDF udf;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/ColumnDescriptionImpl.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/ColumnDescriptionImpl.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/ColumnDescriptionImpl.java
new file mode 100644
index 0000000..6d095e3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/ColumnDescriptionImpl.java
@@ -0,0 +1,119 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads;
+
+import org.apache.ambari.view.hive2.client.ColumnDescription;
+
+import java.io.Serializable;
+
+/**
+ * implementation of ColumnDescription which also includes scale and precision.
+ */
+public class ColumnDescriptionImpl implements ColumnDescription, Serializable {
+  private String name;
+  private String type;
+  private int position;
+  /**
+   * can be null
+   */
+  private Integer precision;
+  /**
+   * can be null
+   */
+  private Integer scale;
+
+  public ColumnDescriptionImpl() {
+  }
+
+  public ColumnDescriptionImpl(String name, String type, int position) {
+    this.name = name;
+    this.type = type;
+    this.position = position;
+  }
+
+  public ColumnDescriptionImpl(String name, String type, int position, int precision) {
+    this.name = name;
+    this.type = type;
+    this.position = position;
+    this.precision = precision;
+  }
+
+  public ColumnDescriptionImpl(String name, String type, int position, int precision, int scale) {
+    this.name = name;
+    this.type = type;
+    this.position = position;
+    this.precision = precision;
+    this.scale = scale;
+  }
+
+  @Override
+  public String getName() {
+    return name;
+  }
+
+  @Override
+  public String getType() {
+    return type;
+  }
+
+  @Override
+  public int getPosition() {
+    return this.position;
+  }
+
+  public Integer getPrecision() {
+    return precision;
+  }
+
+  public Integer getScale() {
+    return scale;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ColumnDescriptionImpl that = (ColumnDescriptionImpl) o;
+
+    if (position != that.position) return false;
+    if (!name.equals(that.name)) return false;
+    return type.equals(that.type);
+
+  }
+
+  @Override
+  public int hashCode() {
+    int result = name.hashCode();
+    result = 31 * result + type.hashCode();
+    result = 31 * result + position;
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return new StringBuilder().append("ColumnDescriptionImpl[")
+            .append("name : ").append(name)
+            .append(", type : " + type)
+            .append(", position : " + position)
+            .append(", precision : " + precision)
+            .append(", scale : " + scale)
+            .append("]").toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/HiveFileType.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/HiveFileType.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/HiveFileType.java
new file mode 100644
index 0000000..82217eb
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/HiveFileType.java
@@ -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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads;
+
+public enum HiveFileType {
+  SEQUENCEFILE,
+  TEXTFILE,
+  RCFILE,
+  ORC,
+  PARQUET,
+  AVRO,
+  INPUTFORMAT;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/TableDataReader.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/TableDataReader.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/TableDataReader.java
new file mode 100644
index 0000000..d7dba85
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/TableDataReader.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads;
+
+import org.apache.ambari.view.hive2.client.Row;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Iterator;
+
+/**
+ * Takes row iterator as input.
+ * iterate over rows and creates a CSV formated stream separating rows by endline "\n"
+ * Note : column values should not contain "\n".
+ */
+public class TableDataReader extends Reader {
+
+  private static final int CAPACITY = 1024;
+  private StringReader stringReader = new StringReader("");
+
+  private Iterator<Row> iterator;
+  private static final CSVFormat CSV_FORMAT = CSVFormat.DEFAULT.withRecordSeparator("\n");
+
+  public TableDataReader(Iterator<Row> rowIterator) {
+    this.iterator = rowIterator;
+  }
+
+  @Override
+  public int read(char[] cbuf, int off, int len) throws IOException {
+
+    int totalLen = len;
+    int count = 0;
+    do {
+      int n = stringReader.read(cbuf, off, len);
+
+      if (n != -1) {
+        // n  were read
+        len = len - n; // len more to be read
+        off = off + n; // off now shifted to n more
+        count += n;
+      }
+
+      if (count == totalLen) return count; // all totalLen characters were read
+
+      if (iterator.hasNext()) { // keep reading as long as we keep getting rows
+        StringWriter stringWriter = new StringWriter(CAPACITY);
+        CSVPrinter csvPrinter = new CSVPrinter(stringWriter, CSV_FORMAT);
+        Row row = iterator.next();
+        csvPrinter.printRecord(row.getRow());
+        stringReader.close(); // close the old string reader
+        stringReader = new StringReader(stringWriter.getBuffer().toString());
+        csvPrinter.close();
+        stringWriter.close();
+      } else {
+        return count == 0 ? -1 : count;
+      }
+    } while (count < totalLen);
+
+    return count;
+  }
+
+  @Override
+  public void close() throws IOException {
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/TableInput.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/TableInput.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/TableInput.java
new file mode 100644
index 0000000..9c27b24
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/TableInput.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads;
+
+import java.util.List;
+
+/**
+ * used as input in REST call
+ */
+class TableInput {
+  public Boolean isFirstRowHeader = Boolean.FALSE;
+  public List<ColumnDescriptionImpl> header;
+  public String tableName;
+  public String databaseName;
+  /**
+   * the format of the file created for the table inside hive : ORC TEXTFILE etc.
+   */
+  public String fileType;
+
+  public TableInput() {
+  }
+
+  public Boolean getIsFirstRowHeader() {
+    return isFirstRowHeader;
+  }
+
+  public void setIsFirstRowHeader(Boolean isFirstRowHeader) {
+    this.isFirstRowHeader = isFirstRowHeader;
+  }
+
+  public List<ColumnDescriptionImpl> getHeader() {
+    return header;
+  }
+
+  public void setHeader(List<ColumnDescriptionImpl> header) {
+    this.header = header;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public void setTableName(String tableName) {
+    this.tableName = tableName;
+  }
+
+  public String getDatabaseName() {
+    return databaseName;
+  }
+
+  public void setDatabaseName(String databaseName) {
+    this.databaseName = databaseName;
+  }
+
+  public String getFileType() {
+    return fileType;
+  }
+
+  public void setFileType(String fileType) {
+    this.fileType = fileType;
+  }
+
+  public void validate(){
+    if( null == this.getFileType()){
+      throw new IllegalArgumentException("fileType parameter cannot be null.");
+    }
+    if( null == this.getTableName()){
+      throw new IllegalArgumentException("tableName parameter cannot be null.");
+    }
+    if( null == this.getDatabaseName()){
+      throw new IllegalArgumentException("databaseName parameter cannot be null.");
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/UploadFromHdfsInput.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/UploadFromHdfsInput.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/UploadFromHdfsInput.java
new file mode 100644
index 0000000..7a7f77c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/UploadFromHdfsInput.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads;
+
+import java.io.Serializable;
+
+public class UploadFromHdfsInput implements Serializable{
+  private Boolean isFirstRowHeader;
+  private String inputFileType;
+  private String hdfsPath;
+  private String tableName;
+  private String databaseName;
+
+  public UploadFromHdfsInput() {
+  }
+
+  public UploadFromHdfsInput(Boolean isFirstRowHeader, String inputFileType, String hdfsPath, String tableName, String databaseName) {
+    this.isFirstRowHeader = isFirstRowHeader;
+    this.inputFileType = inputFileType;
+    this.hdfsPath = hdfsPath;
+    this.tableName = tableName;
+    this.databaseName = databaseName;
+  }
+
+  public Boolean getIsFirstRowHeader() {
+    return isFirstRowHeader;
+  }
+
+  public void setIsFirstRowHeader(Boolean firstRowHeader) {
+    isFirstRowHeader = firstRowHeader;
+  }
+
+  public String getInputFileType() {
+    return inputFileType;
+  }
+
+  public void setInputFileType(String inputFileType) {
+    this.inputFileType = inputFileType;
+  }
+
+  public String getHdfsPath() {
+    return hdfsPath;
+  }
+
+  public void setHdfsPath(String hdfsPath) {
+    this.hdfsPath = hdfsPath;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public void setTableName(String tableName) {
+    this.tableName = tableName;
+  }
+
+  public String getDatabaseName() {
+    return databaseName;
+  }
+
+  public void setDatabaseName(String databaseName) {
+    this.databaseName = databaseName;
+  }
+
+  @Override
+  public String toString() {
+    return "UploadFromHdfsInput{" +
+            "isFirstRowHeader=" + isFirstRowHeader +
+            ", inputFileType='" + inputFileType + '\'' +
+            ", hdfsPath='" + hdfsPath + '\'' +
+            ", tableName='" + tableName + '\'' +
+            ", databaseName='" + databaseName + '\'' +
+            '}';
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/UploadService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/UploadService.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/UploadService.java
new file mode 100644
index 0000000..59e969d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/UploadService.java
@@ -0,0 +1,463 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads;
+
+import com.sun.jersey.core.header.FormDataContentDisposition;
+import com.sun.jersey.multipart.FormDataParam;
+import org.apache.ambari.view.hive2.BaseService;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.Job;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobController;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobImpl;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobResourceManager;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.DataParser;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.ParseOptions;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.PreviewData;
+import org.apache.ambari.view.hive2.resources.uploads.query.*;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.apache.ambari.view.hive2.utils.SharedObjectsFactory;
+import org.apache.ambari.view.utils.ambari.AmbariApi;
+import org.apache.commons.io.input.ReaderInputStream;
+import org.apache.hadoop.fs.FSDataInputStream;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.json.simple.JSONObject;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.*;
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+
+/**
+ * UI driven end points for creation of new hive table and inserting data into it.
+ * It uploads a file, parses it partially based on its type, generates preview,
+ * creates temporary hive table for storage as CSV and actual hive table,
+ * uploads the file again, parses it, create CSV stream and upload to hdfs in temporary table,
+ * insert rows from temporary table to actual table, delete temporary table.
+ * <p/>
+ * API:
+ * POST /preview : takes stream, parses it and returns preview rows, headers and column type suggestions
+ * POST /createTable : runs hive query to create table in hive
+ * POST /upload : takes stream, parses it and converts it into CSV and uploads it to the temporary table
+ * POST /insertIntoTable : runs hive query to insert data from temporary table to actual hive table
+ * POST /deleteTable : deletes the temporary table
+ */
+public class UploadService extends BaseService {
+
+  private AmbariApi ambariApi;
+  protected JobResourceManager resourceManager;
+
+  final private static String HIVE_METASTORE_LOCATION_KEY = "hive.metastore.warehouse.dir";
+  final private static String HIVE_SITE = "hive-site";
+  final private static String HIVE_METASTORE_LOCATION_KEY_VIEW_PROPERTY = HIVE_METASTORE_LOCATION_KEY;
+  private static final String HIVE_DEFAULT_METASTORE_LOCATION = "/apps/hive/warehouse" ;
+  final private static String HIVE_DEFAULT_DB = "default";
+
+  public void validateForUploadFile(UploadFromHdfsInput input){
+    if( null == input.getInputFileType()){
+      throw new IllegalArgumentException("inputFileType parameter cannot be null.");
+    }
+    if( null == input.getHdfsPath()){
+      throw new IllegalArgumentException("hdfsPath parameter cannot be null.");
+    }
+    if( null == input.getTableName()){
+      throw new IllegalArgumentException("tableName parameter cannot be null.");
+    }
+    if( null == input.getDatabaseName()){
+      throw new IllegalArgumentException("databaseName parameter cannot be null.");
+    }
+
+    if( input.getIsFirstRowHeader() == null ){
+      input.setIsFirstRowHeader(false);
+    }
+  }
+
+  public void validateForPreview(UploadFromHdfsInput input){
+    if( input.getIsFirstRowHeader() == null ){
+      input.setIsFirstRowHeader(false);
+    }
+
+    if( null == input.getInputFileType()){
+      throw new IllegalArgumentException("inputFileType parameter cannot be null.");
+    }
+    if( null == input.getHdfsPath()){
+      throw new IllegalArgumentException("hdfsPath parameter cannot be null.");
+    }
+  }
+
+  @POST
+  @Path("/previewFromHdfs")
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response uploadForPreviewFromHDFS(UploadFromHdfsInput input) {
+
+    InputStream uploadedInputStream = null;
+    try {
+      uploadedInputStream = getHDFSFileStream(input.getHdfsPath());
+      this.validateForPreview(input);
+      PreviewData pd = generatePreview(input.getIsFirstRowHeader(), input.getInputFileType(), uploadedInputStream);
+      String tableName = getBasenameFromPath(input.getHdfsPath());
+      return createPreviewResponse(pd, input.getIsFirstRowHeader(),tableName);
+    } catch (Exception e) {
+      LOG.error("Exception occurred while generating preview for hdfs file : " + input.getHdfsPath(), e);
+      throw new ServiceFormattedException(e.getMessage(), e);
+    } finally {
+      if (null != uploadedInputStream) {
+        try {
+          uploadedInputStream.close();
+        } catch (IOException e) {
+          LOG.error("Exception occured while closing the HDFS file stream for path " + input.getHdfsPath(), e);
+        }
+      }
+    }
+  }
+
+  @POST
+  @Path("/preview")
+  @Consumes(MediaType.MULTIPART_FORM_DATA)
+  public Response uploadForPreview(
+    @FormDataParam("file") InputStream uploadedInputStream,
+    @FormDataParam("file") FormDataContentDisposition fileDetail,
+    @FormDataParam("isFirstRowHeader") Boolean isFirstRowHeader,
+    @FormDataParam("inputFileType") String inputFileType
+  ) {
+    try {
+      if( null == inputFileType)
+        throw new IllegalArgumentException("inputFileType parameter cannot be null.");
+
+      if( null == isFirstRowHeader )
+        isFirstRowHeader = false;
+
+      PreviewData pd = generatePreview(isFirstRowHeader, inputFileType, uploadedInputStream);
+      return createPreviewResponse(pd, isFirstRowHeader,getBasename(fileDetail.getFileName()));
+    } catch (Exception e) {
+      LOG.error("Exception occurred while generating preview for local file", e);
+      throw new ServiceFormattedException(e.getMessage(), e);
+    }
+  }
+
+
+  @Path("/createTable")
+  @POST
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response createTable(TableInput tableInput) {
+    try {
+      tableInput.validate();
+      List<ColumnDescriptionImpl> header = tableInput.getHeader();
+      String databaseName = tableInput.getDatabaseName();
+      String tableName = tableInput.getTableName();
+      Boolean isFirstRowHeader = tableInput.getIsFirstRowHeader();
+      String fileTypeStr = tableInput.getFileType();
+      HiveFileType hiveFileType = HiveFileType.valueOf(fileTypeStr);
+
+      TableInfo ti = new TableInfo(databaseName, tableName, header, hiveFileType);
+      String tableCreationQuery = generateCreateQuery(ti);
+
+      LOG.info("tableCreationQuery : {}", tableCreationQuery);
+
+      Job actualTableJob = createJob(tableCreationQuery, databaseName);
+      String actualTableJobId = actualTableJob.getId();
+
+      JSONObject jobObject = new JSONObject();
+      jobObject.put("jobId", actualTableJobId);
+
+      LOG.info("table creation jobId {}", actualTableJobId);
+      return Response.ok(jobObject).status(201).build();
+    } catch (Throwable e) {
+      LOG.error("Exception occurred while creating table with input : " + tableInput, e);
+      throw new ServiceFormattedException(e.getMessage(), e);
+    }
+  }
+
+  @Path("/uploadFromHDFS")
+  @POST
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response uploadFileFromHdfs(UploadFromHdfsInput input ) {
+    this.validateForUploadFile(input);
+
+    if (ParseOptions.InputFileType.CSV.toString().equals(input.getInputFileType()) && Boolean.FALSE.equals(input.getIsFirstRowHeader())) {
+      // upload using the LOAD query
+      LoadQueryInput loadQueryInput = new LoadQueryInput(input.getHdfsPath(), input.getDatabaseName(), input.getTableName());
+      String loadQuery = new QueryGenerator().generateLoadQuery(loadQueryInput);
+
+      try {
+        Job job = createJob(loadQuery,  input.getDatabaseName());
+
+        JSONObject jo = new JSONObject();
+        jo.put("jobId", job.getId());
+
+        return Response.ok(jo).build();
+      } catch (Throwable e) {
+        LOG.error("Exception occurred while creating job for Load From HDFS query : " + loadQuery, e);
+        throw new ServiceFormattedException(e.getMessage(), e);
+      }
+
+    } else {
+      // create stream and upload
+      InputStream hdfsStream = null;
+      try {
+        hdfsStream = getHDFSFileStream(input.getHdfsPath());
+        String path = uploadFileFromStream(hdfsStream, input.getIsFirstRowHeader(),input.getInputFileType(),input.getTableName(), input.getDatabaseName());
+
+        JSONObject jo = new JSONObject();
+        jo.put("uploadedPath", path);
+
+        return Response.ok(jo).build();
+      } catch (Exception e) {
+        LOG.error("Exception occurred while uploading the file from HDFS with path : " + input.getHdfsPath(), e);
+        throw new ServiceFormattedException(e.getMessage(), e);
+      } finally {
+        if (null != hdfsStream)
+          try {
+            hdfsStream.close();
+          } catch (IOException e) {
+            LOG.error("Exception occured while closing the HDFS stream for path : " + input.getHdfsPath(), e);
+          }
+      }
+    }
+  }
+
+  @Path("/upload")
+  @POST
+  @Consumes(MediaType.MULTIPART_FORM_DATA)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response uploadFile(
+    @FormDataParam("file") InputStream uploadedInputStream,
+    @FormDataParam("file") FormDataContentDisposition fileDetail,
+    @FormDataParam("isFirstRowHeader") Boolean isFirstRowHeader,
+    @FormDataParam("inputFileType") String inputFileType,   // the format of the file uploaded. CSV/JSON etc.
+    @FormDataParam("tableName") String tableName,
+    @FormDataParam("databaseName") String databaseName
+  ) {
+    try {
+
+      String path = uploadFileFromStream(uploadedInputStream,isFirstRowHeader,inputFileType,tableName,databaseName);
+
+      JSONObject jo = new JSONObject();
+      jo.put("uploadedPath", path);
+      return Response.ok(jo).build();
+    } catch (Exception e) {
+      throw new ServiceFormattedException(e.getMessage(), e);
+    }
+  }
+
+  @Path("/insertIntoTable")
+  @POST
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response insertFromTempTable(InsertFromQueryInput input) {
+    try {
+      String insertQuery = generateInsertFromQuery(input);
+      LOG.info("insertQuery : {}", insertQuery);
+
+      Job job = createJob(insertQuery, "default");
+
+      JSONObject jo = new JSONObject();
+      jo.put("jobId", job.getId());
+
+      return Response.ok(jo).build();
+    } catch (Throwable e) {
+      throw new ServiceFormattedException(e.getMessage(), e);
+    }
+  }
+
+  @Path("/deleteTable")
+  @POST
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response deleteTable(DeleteQueryInput input) {
+    try {
+      String deleteQuery = generateDeleteQuery(input);
+      LOG.info("deleteQuery : {}", deleteQuery);
+
+      Job job = createJob(deleteQuery, "default");
+
+      JSONObject jo = new JSONObject();
+      jo.put("jobId", job.getId());
+
+      return Response.ok(jo).build();
+    } catch (Throwable e) {
+      throw new ServiceFormattedException(e.getMessage(), e);
+    }
+  }
+
+  private String uploadIntoTable(Reader reader, String databaseName, String tempTableName) {
+    try {
+      String basePath = getHiveMetaStoreLocation();
+
+      if (!basePath.endsWith("/")) {
+        basePath = basePath + "/";
+      }
+
+      if (databaseName != null && !databaseName.equals(HIVE_DEFAULT_DB)) {
+        basePath = basePath + databaseName + ".db/";
+      }
+
+      String fullPath = basePath + tempTableName + "/" + tempTableName + ".csv";
+
+      LOG.info("Uploading file into : {}", fullPath);
+
+      uploadFile(fullPath, new ReaderInputStream(reader));
+
+      return fullPath;
+    } catch (Exception e) {
+      throw new ServiceFormattedException(e.getMessage(), e);
+    }
+  }
+
+  private synchronized JobResourceManager getResourceManager() {
+    if (resourceManager == null) {
+      SharedObjectsFactory connectionsFactory = getSharedObjectsFactory();
+      resourceManager = new JobResourceManager(connectionsFactory, context);
+    }
+    return resourceManager;
+  }
+
+  private synchronized AmbariApi getAmbariApi() {
+    if (null == ambariApi) {
+      ambariApi = new AmbariApi(this.context);
+    }
+    return ambariApi;
+  }
+
+  private String generateCreateQuery(TableInfo ti) {
+    return new QueryGenerator().generateCreateQuery(ti);
+  }
+
+  private String generateInsertFromQuery(InsertFromQueryInput input) {
+    return new QueryGenerator().generateInsertFromQuery(input);
+  }
+
+  private String generateDeleteQuery(DeleteQueryInput deleteQueryInput) {
+    return new QueryGenerator().generateDropTableQuery(deleteQueryInput);
+  }
+
+  private Job createJob(String query, String databaseName) throws Throwable {
+    Map jobInfo = new HashMap<String, String>();
+    jobInfo.put("title", "Internal Table Creation");
+    jobInfo.put("forcedContent", query);
+    jobInfo.put("dataBase", databaseName);
+
+    LOG.info("jobInfo : " + jobInfo);
+    Job job = new JobImpl(jobInfo);
+    LOG.info("job : " + job);
+    getResourceManager().create(job);
+
+    JobController createdJobController = getResourceManager().readController(job.getId());
+    createdJobController.submit();
+    getResourceManager().saveIfModified(createdJobController);
+
+    return job;
+  }
+
+  private String getHiveMetaStoreLocation() {
+    String dir = context.getProperties().get(HIVE_METASTORE_LOCATION_KEY_VIEW_PROPERTY);
+    if(dir != null && !dir.trim().isEmpty()){
+      return dir;
+    }else{
+      LOG.debug("Neither found associated cluster nor found the view property {}. Returning default location : {}", HIVE_METASTORE_LOCATION_KEY_VIEW_PROPERTY, HIVE_DEFAULT_METASTORE_LOCATION);
+      return HIVE_DEFAULT_METASTORE_LOCATION;
+    }
+  }
+
+  private void uploadFile(final String filePath, InputStream uploadedInputStream)
+    throws IOException, InterruptedException {
+    byte[] chunk = new byte[1024];
+    FSDataOutputStream out = getSharedObjectsFactory().getHdfsApi().create(filePath, false);
+    int n = -1;
+    while ((n = uploadedInputStream.read(chunk)) != -1) {
+      out.write(chunk, 0, n);
+    }
+    out.close();
+  }
+
+  private PreviewData generatePreview(Boolean isFirstRowHeader, String inputFileType, InputStream uploadedInputStream) throws Exception {
+    ParseOptions parseOptions = new ParseOptions();
+    parseOptions.setOption(ParseOptions.OPTIONS_FILE_TYPE, inputFileType);
+    if (inputFileType.equals(ParseOptions.InputFileType.CSV.toString())){
+      if(isFirstRowHeader)
+        parseOptions.setOption(ParseOptions.OPTIONS_HEADER, ParseOptions.HEADER.FIRST_RECORD.toString());
+      else
+        parseOptions.setOption(ParseOptions.OPTIONS_HEADER, ParseOptions.HEADER.NONE.toString());
+    }
+    else
+      parseOptions.setOption(ParseOptions.OPTIONS_HEADER, ParseOptions.HEADER.EMBEDDED.toString());
+
+    LOG.info("isFirstRowHeader : {}, inputFileType : {}", isFirstRowHeader, inputFileType);
+
+    DataParser dataParser = new DataParser(new InputStreamReader(uploadedInputStream), parseOptions);
+
+    return dataParser.parsePreview();
+  }
+
+  private Response createPreviewResponse(PreviewData pd, Boolean isFirstRowHeader, String tableName) {
+    Map<String, Object> retData = new HashMap<String, Object>();
+    retData.put("header", pd.getHeader());
+    retData.put("rows", pd.getPreviewRows());
+    retData.put("isFirstRowHeader", isFirstRowHeader);
+    retData.put("tableName", tableName);
+
+    JSONObject jsonObject = new JSONObject(retData);
+    return Response.ok(jsonObject).build();
+  }
+
+  private InputStream getHDFSFileStream(String path) throws IOException, InterruptedException {
+    FSDataInputStream fsStream = getSharedObjectsFactory().getHdfsApi().open(path);
+    return fsStream;
+  }
+
+  private String uploadFileFromStream(
+    InputStream uploadedInputStream,
+    Boolean isFirstRowHeader,
+    String inputFileType,   // the format of the file uploaded. CSV/JSON etc.
+    String tableName,
+    String databaseName
+
+  ) throws Exception {
+    LOG.info(" uploading file into databaseName {}, tableName {}", databaseName, tableName);
+    ParseOptions parseOptions = new ParseOptions();
+    parseOptions.setOption(ParseOptions.OPTIONS_FILE_TYPE, inputFileType);
+
+    DataParser dataParser = new DataParser(new InputStreamReader(uploadedInputStream), parseOptions);
+
+    if (inputFileType.equals(ParseOptions.InputFileType.CSV.toString()) && isFirstRowHeader)
+      dataParser.extractHeader(); // removes the header line if any from the stream
+
+    Reader csvReader = dataParser.getTableDataReader();
+    String path = uploadIntoTable(csvReader, databaseName, tableName);
+    return path;
+  }
+
+  private String getBasenameFromPath(String path) {
+    String fileName = new File(path).getName();
+    return getBasename(fileName);
+  }
+
+  private String getBasename(String fileName){
+    int index = fileName.indexOf(".");
+    if(index != -1){
+      return fileName.substring(0,index);
+    }
+
+    return fileName;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/DataParser.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/DataParser.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/DataParser.java
new file mode 100644
index 0000000..6edc97c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/DataParser.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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers;
+
+import org.apache.ambari.view.hive2.client.Row;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.csv.CSVParser;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.json.JSONParser;
+import org.apache.ambari.view.hive2.resources.uploads.parsers.xml.XMLParser;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Iterator;
+
+/**
+ * Wrapper/Decorator over the Stream parsers.
+ * Supports XML/JSON/CSV parsing.
+ */
+public class DataParser implements IParser {
+
+  private IParser parser;
+
+  public DataParser(Reader reader, ParseOptions parseOptions) throws IOException {
+    if (parseOptions.getOption(ParseOptions.OPTIONS_FILE_TYPE).equals(ParseOptions.InputFileType.CSV.toString())) {
+      parser = new CSVParser(reader, parseOptions);
+    } else if (parseOptions.getOption(ParseOptions.OPTIONS_FILE_TYPE).equals(ParseOptions.InputFileType.JSON.toString())) {
+      parser = new JSONParser(reader, parseOptions);
+    } else if (parseOptions.getOption(ParseOptions.OPTIONS_FILE_TYPE).equals(ParseOptions.InputFileType.XML.toString())) {
+      parser = new XMLParser(reader, parseOptions);
+    }
+  }
+
+  @Override
+  public Reader getTableDataReader() {
+    return parser.getTableDataReader();
+  }
+
+  @Override
+  public PreviewData parsePreview() {
+    return parser.parsePreview();
+  }
+
+  @Override
+  public Row extractHeader() {
+    return parser.extractHeader();
+  }
+
+  @Override
+  public void close() throws IOException {
+    parser.close();
+  }
+
+  @Override
+  public Iterator<Row> iterator() {
+    return parser.iterator();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/EndOfDocumentException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/EndOfDocumentException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/EndOfDocumentException.java
new file mode 100644
index 0000000..f5adc4e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/EndOfDocumentException.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers;
+
+
+public class EndOfDocumentException extends Exception {
+  public EndOfDocumentException() {
+  }
+
+  public EndOfDocumentException(String message) {
+    super(message);
+  }
+
+  public EndOfDocumentException(String message, Throwable cause) {
+    super(message, cause);
+  }
+
+  public EndOfDocumentException(Throwable cause) {
+    super(cause);
+  }
+
+  public EndOfDocumentException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+    super(message, cause, enableSuppression, writableStackTrace);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/IParser.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/IParser.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/IParser.java
new file mode 100644
index 0000000..401ef48
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/IParser.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers;
+
+import org.apache.ambari.view.hive2.client.Row;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * Interface defining methods for Parsers that can used for generating preview
+ * and uploading table into hive.
+ */
+public interface IParser extends Iterable<Row> {
+
+  /**
+   * @return returns the Reader that can be read to get the table data as CSV Text Data that can be uploaded directly
+   * to HDFS
+   */
+  Reader getTableDataReader();
+
+  PreviewData parsePreview();
+
+  Row extractHeader();
+
+  void close() throws IOException;
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/ParseOptions.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/ParseOptions.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/ParseOptions.java
new file mode 100644
index 0000000..53af85a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/ParseOptions.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers;
+
+import java.util.HashMap;
+
+public class ParseOptions {
+  public enum InputFileType {
+    CSV,
+    JSON,
+    XML
+  }
+
+  public enum HEADER {
+    FIRST_RECORD,
+    PROVIDED_BY_USER, // not used right now but can be used when some metadata of file provide this information
+    EMBEDDED, // this one is for JSON/ XML and may be other file formats where its embedded with the data
+    NONE   // if the file does not contain header information at all
+  }
+  final public static String OPTIONS_FILE_TYPE = "FILE_TYPE";
+  final public static String OPTIONS_HEADER = "HEADER";
+  final public static String OPTIONS_NUMBER_OF_PREVIEW_ROWS = "NUMBER_OF_PREVIEW_ROWS";
+
+  private HashMap<String, Object> options = new HashMap<>();
+
+  public void setOption(String key, Object value) {
+    this.options.put(key, value);
+  }
+
+  public Object getOption(String key) {
+    return this.options.get(key);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/ParseUtils.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/ParseUtils.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/ParseUtils.java
new file mode 100644
index 0000000..fefacce
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/uploads/parsers/ParseUtils.java
@@ -0,0 +1,133 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.uploads.parsers;
+
+import org.apache.ambari.view.hive2.client.ColumnDescription;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class ParseUtils {
+
+  final public static String[] DATE_FORMATS = {"mm/dd/yyyy", "dd/mm/yyyy", "mm-dd-yyyy" /*add more formatss*/};
+
+  public static boolean isInteger(Object object) {
+    if (object == null)
+      return false;
+
+    if (object instanceof Integer)
+      return true;
+
+    try {
+      Integer i = Integer.parseInt(object.toString());
+      return true;
+    } catch (NumberFormatException nfe) {
+      return false;
+    }
+  }
+
+  public static boolean isBoolean(Object object) {
+    if (object == null)
+      return false;
+
+    if (object instanceof Boolean)
+      return true;
+
+    String strValue = object.toString();
+    if (strValue.equalsIgnoreCase("true") || strValue.equalsIgnoreCase("false"))
+      return true;
+    else
+      return false;
+  }
+
+  public static boolean isLong(Object object) {
+    if (object == null)
+      return false;
+
+    if (object instanceof Long)
+      return true;
+
+    try {
+      Long i = Long.parseLong(object.toString());
+      return true;
+    } catch (Exception nfe) {
+      return false;
+    }
+  }
+
+  public static boolean isDouble(Object object) {
+    if (object == null)
+      return false;
+
+    if (object instanceof Double)
+      return true;
+
+    try {
+      Double i = Double.parseDouble(object.toString());
+      return true;
+    } catch (Exception nfe) {
+      return false;
+    }
+  }
+
+  public static boolean isChar(Object object) {
+    if (object == null)
+      return false;
+
+    if (object instanceof Character)
+      return true;
+
+    String str = object.toString().trim();
+    if (str.length() == 1)
+      return true;
+
+    return false;
+  }
+
+  public static boolean isDate(Object object) {
+    if (object == null)
+      return false;
+
+    if (object instanceof Date)
+      return true;
+
+    String str = object.toString();
+    for (String format : DATE_FORMATS) {
+      try {
+        Date i = new SimpleDateFormat(format).parse(str);
+        return true;
+      } catch (Exception e) {
+      }
+    }
+
+    return false;
+  }
+
+  public static ColumnDescription.DataTypes detectHiveDataType(Object object) {
+    // detect Integer
+    if (isInteger(object)) return ColumnDescription.DataTypes.INT;
+    if (isLong(object)) return ColumnDescription.DataTypes.BIGINT;
+    if (isBoolean(object)) return ColumnDescription.DataTypes.BOOLEAN;
+    if (isDouble(object)) return ColumnDescription.DataTypes.DOUBLE;
+    if (isDate(object)) return ColumnDescription.DataTypes.DATE;
+    if (isChar(object)) return ColumnDescription.DataTypes.CHAR;
+
+    return ColumnDescription.DataTypes.STRING;
+  }
+}


[16/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/PersonalCRUDResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/PersonalCRUDResourceManager.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/PersonalCRUDResourceManager.java
new file mode 100644
index 0000000..2c774df
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/PersonalCRUDResourceManager.java
@@ -0,0 +1,99 @@
+/**
+ * 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.ambari.view.hive2.resources;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.IStorageFactory;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.persistence.utils.PersonalResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Resource manager that returns only user owned elements from DB
+ * @param <T> Data type with ID and Owner
+ */
+public class PersonalCRUDResourceManager<T extends PersonalResource> extends CRUDResourceManager<T> {
+  protected boolean ignorePermissions = false;
+
+  private final static Logger LOG =
+      LoggerFactory.getLogger(PersonalCRUDResourceManager.class);
+  protected ViewContext context;
+
+  /**
+   * Constructor
+   * @param resourceClass model class
+   */
+  public PersonalCRUDResourceManager(Class<? extends T> resourceClass, IStorageFactory storageFabric, ViewContext context) {
+    super(resourceClass, storageFabric);
+    this.context = context;
+  }
+
+  @Override
+  public T update(T newObject, String id) throws ItemNotFound {
+    T object = storageFactory.getStorage().load(this.resourceClass, id);
+    if (object.getOwner().compareTo(this.context.getUsername()) != 0) {
+      throw new ItemNotFound();
+    }
+
+    newObject.setOwner(this.context.getUsername());
+    return super.update(newObject, id);
+  }
+
+  @Override
+  public T save(T object) {
+    if (!ignorePermissions) {
+      // in threads permissions should be ignored,
+      // because context.getUsername doesn't work. See BUG-27093.
+      object.setOwner(this.context.getUsername());
+    }
+    return super.save(object);
+  }
+
+  @Override
+  protected boolean checkPermissions(T object) {
+    if (ignorePermissions) {
+      return true;
+    }
+    return object.getOwner().compareTo(this.context.getUsername()) == 0;
+  }
+
+  /**
+   * Execute action ignoring objects owner
+   * @param actions callable to execute
+   * @return value returned from actions
+   * @throws Exception
+   */
+  public T ignorePermissions(Callable<T> actions) throws Exception {
+    ignorePermissions = true;
+    T result;
+    try {
+      result = actions.call();
+    } finally {
+      ignorePermissions = false;
+    }
+    return result;
+  }
+
+  protected String getUsername() {
+    return context.getUsername();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/SharedCRUDResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/SharedCRUDResourceManager.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/SharedCRUDResourceManager.java
new file mode 100644
index 0000000..3942276
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/SharedCRUDResourceManager.java
@@ -0,0 +1,44 @@
+/**
+ * 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.ambari.view.hive2.resources;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.IStorageFactory;
+import org.apache.ambari.view.hive2.persistence.utils.Indexed;
+
+/**
+ * Resource manager that doesn't restrict access (Allow all)
+ * @param <T> Data type with ID
+ */
+public class SharedCRUDResourceManager<T extends Indexed> extends CRUDResourceManager<T> {
+  protected ViewContext context;
+
+  /**
+   * Constructor
+   * @param responseClass model class
+   */
+  public SharedCRUDResourceManager(Class<T> responseClass, IStorageFactory storageFabric) {
+    super(responseClass, storageFabric);
+  }
+
+  @Override
+  protected boolean checkPermissions(T object) {
+    return true; //everyone has permission
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/HiveBrowserService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/HiveBrowserService.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/HiveBrowserService.java
new file mode 100644
index 0000000..0da49c4
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/HiveBrowserService.java
@@ -0,0 +1,261 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.browser;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive2.client.ColumnDescription;
+import org.apache.ambari.view.hive2.client.ConnectionConfig;
+import org.apache.ambari.view.hive2.client.Cursor;
+import org.apache.ambari.view.hive2.client.DDLDelegator;
+import org.apache.ambari.view.hive2.client.DDLDelegatorImpl;
+import org.apache.ambari.view.hive2.client.Row;
+import org.apache.ambari.view.hive2.resources.jobs.ResultsPaginationController;
+import org.apache.ambari.view.hive2.utils.BadRequestFormattedException;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.apache.ambari.view.hive2.ConnectionFactory;
+import org.apache.ambari.view.hive2.ConnectionSystem;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * Database access resource
+ */
+public class HiveBrowserService {
+  @Inject
+  ViewResourceHandler handler;
+  @Inject
+  protected ViewContext context;
+
+  protected final static Logger LOG =
+    LoggerFactory.getLogger(HiveBrowserService.class);
+
+  /**
+   * Returns list of databases
+   */
+  @GET
+  @Path("database")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response databases(@QueryParam("like") String like,
+                            @QueryParam("first") String fromBeginning,
+                            @QueryParam("count") Integer count,
+                            @QueryParam("columns") final String requestedColumns) {
+    if (like == null)
+      like = "*";
+    else
+      like = "*" + like + "*";
+    JSONObject response = new JSONObject();
+    DDLDelegator delegator = new DDLDelegatorImpl(context, ConnectionSystem.getInstance().getActorSystem(), ConnectionSystem.getInstance().getOperationController(context));
+    List<String> databases = delegator.getDbList(getHiveConnectionConfig(), like);
+    response.put("databases", databases);
+    return Response.ok(response).build();
+
+  }
+
+  /**
+   * Returns list of databases
+   */
+  @GET
+  @Path("database.page")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response databasesPaginated(@QueryParam("like") String like,
+                                     @QueryParam("first") String fromBeginning,
+                                     @QueryParam("count") Integer count,
+                                     @QueryParam("searchId") String searchId,
+                                     @QueryParam("format") String format,
+                                     @QueryParam("columns") final String requestedColumns) {
+    if (like == null)
+      like = "*";
+    else
+      like = "*" + like + "*";
+    String curl = null;
+    try {
+      final String finalLike = like;
+      final DDLDelegator delegator = new DDLDelegatorImpl(context, ConnectionSystem.getInstance().getActorSystem(), ConnectionSystem.getInstance().getOperationController(context));
+      return ResultsPaginationController.getInstance(context)
+          .request("databases", searchId, false, fromBeginning, count, format, requestedColumns,
+            new Callable<Cursor<Row, ColumnDescription>>() {
+              @Override
+              public Cursor<Row, ColumnDescription> call() throws Exception {
+                return delegator.getDbListCursor(getHiveConnectionConfig(), finalLike);
+              }
+            }).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (IllegalArgumentException ex) {
+      throw new BadRequestFormattedException(ex.getMessage(), ex);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex, curl);
+    }
+  }
+
+  /**
+   * Returns list of databases
+   */
+  @GET
+  @Path("database/{db}/table")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response tablesInDatabase(@PathParam("db") String db,
+                                   @QueryParam("like") String like,
+                                   @QueryParam("first") String fromBeginning,
+                                   @QueryParam("count") Integer count,
+                                   @QueryParam("columns") final String requestedColumns) {
+    if (like == null)
+      like = "*";
+    else
+      like = "*" + like + "*";
+
+    JSONObject response = new JSONObject();
+    DDLDelegator delegator = new DDLDelegatorImpl(context, ConnectionSystem.getInstance().getActorSystem(), ConnectionSystem.getInstance().getOperationController(context));
+    List<String> tables = delegator.getTableList(getHiveConnectionConfig(), db, like);
+    response.put("tables", tables);
+    response.put("database", db);
+    return Response.ok(response).build();
+
+  }
+
+  /**
+   * Returns list of databases
+   */
+  @GET
+  @Path("database/{db}/table.page")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response tablesInDatabasePaginated(@PathParam("db") final String db,
+                                            @QueryParam("like") String like,
+                                            @QueryParam("first") String fromBeginning,
+                                            @QueryParam("count") Integer count,
+                                            @QueryParam("searchId") String searchId,
+                                            @QueryParam("format") String format,
+                                            @QueryParam("columns") final String requestedColumns) {
+    if (like == null)
+      like = "*";
+    else
+      like = "*" + like + "*";
+    String curl = null;
+    try {
+      final String finalLike = like;
+      final DDLDelegator delegator = new DDLDelegatorImpl(context, ConnectionSystem.getInstance().getActorSystem(), ConnectionSystem.getInstance().getOperationController(context));
+      try {
+        return ResultsPaginationController.getInstance(context)
+          .request(db + ":tables:", searchId, false, fromBeginning, count, format, requestedColumns,
+            new Callable<Cursor<Row, ColumnDescription>>() {
+              @Override
+              public Cursor<Row, ColumnDescription> call() throws Exception {
+                return delegator.getTableListCursor(getHiveConnectionConfig(), db, finalLike);
+              }
+            }).build();
+      } catch (Exception ex) {
+        throw new ServiceFormattedException(ex.getMessage(), ex);
+      }
+
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (IllegalArgumentException ex) {
+      throw new BadRequestFormattedException(ex.getMessage(), ex);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex, curl);
+    }
+  }
+
+  /**
+   * Returns list of databases
+   */
+  @GET
+  @Path("database/{db}/table/{table}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response describeTable(@PathParam("db") String db,
+                                @PathParam("table") String table,
+                                @QueryParam("like") String like,
+                                @QueryParam("columns") String requestedColumns,
+                                @QueryParam("extended") String extended) {
+    boolean extendedTableDescription = (extended != null && extended.equals("true"));
+    String curl = null;
+    try {
+      JSONObject response = new JSONObject();
+      DDLDelegator delegator = new DDLDelegatorImpl(context, ConnectionSystem.getInstance().getActorSystem(), ConnectionSystem.getInstance().getOperationController(context));
+      List<ColumnDescription> descriptions = delegator.getTableDescription(getHiveConnectionConfig(), db, table, "%", extendedTableDescription);
+      response.put("columns", descriptions);
+      response.put("database", db);
+      response.put("table", table);
+
+      //TODO: New implementation
+
+      return Response.ok(response).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (IllegalArgumentException ex) {
+      throw new BadRequestFormattedException(ex.getMessage(), ex);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex, curl);
+    }
+  }
+
+  /**
+   * Returns list of databases
+   */
+  @GET
+  @Path("database/{db}/table/{table}.page")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response describeTablePaginated(@PathParam("db") final String db,
+                                         @PathParam("table") final String table,
+                                         @QueryParam("like") String like,
+                                         @QueryParam("first") String fromBeginning,
+                                         @QueryParam("searchId") String searchId,
+                                         @QueryParam("count") Integer count,
+                                         @QueryParam("format") String format,
+                                         @QueryParam("columns") final String requestedColumns) {
+    if (like == null)
+      like = ".*";
+    else
+      like = ".*" + like + ".*";
+    final String finalLike = like;
+
+    final DDLDelegator delegator = new DDLDelegatorImpl(context, ConnectionSystem.getInstance().getActorSystem(), ConnectionSystem.getInstance().getOperationController(context));
+    try {
+      return ResultsPaginationController.getInstance(context)
+        .request(db + ":tables:" + table + ":columns", searchId, false, fromBeginning, count, format, requestedColumns,
+          new Callable<Cursor<Row, ColumnDescription>>() {
+            @Override
+            public Cursor<Row, ColumnDescription> call() throws Exception {
+              return delegator.getTableDescriptionCursor(getHiveConnectionConfig(), db, table, finalLike, false);
+            }
+          }).build();
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+
+  private ConnectionConfig getHiveConnectionConfig() {
+    return ConnectionFactory.create(context);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/files/FileResource.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/files/FileResource.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/files/FileResource.java
new file mode 100644
index 0000000..e8dfce9
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/files/FileResource.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     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.ambari.view.hive2.resources.files;
+
+/**
+ * File bean
+ */
+public class FileResource {
+  private String filePath;
+  private String fileContent;
+  private boolean hasNext;
+  private long page;
+  private long pageCount;
+
+  public String getFilePath() {
+    return filePath;
+  }
+
+  public void setFilePath(String filePath) {
+    this.filePath = filePath;
+  }
+
+  public String getFileContent() {
+    return fileContent;
+  }
+
+  public void setFileContent(String fileContent) {
+    this.fileContent = fileContent;
+  }
+
+  public boolean isHasNext() {
+    return hasNext;
+  }
+
+  public void setHasNext(boolean hasNext) {
+    this.hasNext = hasNext;
+  }
+
+  public long getPage() {
+    return page;
+  }
+
+  public void setPage(long page) {
+    this.page = page;
+  }
+
+  public long getPageCount() {
+    return pageCount;
+  }
+
+  public void setPageCount(long pageCount) {
+    this.pageCount = pageCount;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/files/FileService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/files/FileService.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/files/FileService.java
new file mode 100644
index 0000000..db63364
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/files/FileService.java
@@ -0,0 +1,250 @@
+/**
+ * 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.ambari.view.hive2.resources.files;
+
+import com.jayway.jsonpath.JsonPath;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive2.BaseService;
+import org.apache.ambari.view.hive2.utils.*;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.ambari.view.utils.hdfs.HdfsUtil;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.IOUtils;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.apache.hadoop.fs.FileAlreadyExistsException;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+
+/**
+ * File access resource
+ * API:
+ * GET /:path
+ *      read entire file
+ * POST /
+ *      create new file
+ *      Required: filePath
+ *      file should not already exists
+ * PUT /:path
+ *      update file content
+ */
+public class FileService extends BaseService {
+  public static final String FAKE_FILE = "fakefile://";
+  public static final String JSON_PATH_FILE = "jsonpath:";
+
+  @Inject
+  ViewResourceHandler handler;
+
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(FileService.class);
+
+  /**
+   * Get single item
+   */
+  @GET
+  @Path("{filePath:.*}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getFilePage(@PathParam("filePath") String filePath, @QueryParam("page") Long page) throws IOException, InterruptedException {
+
+    LOG.debug("Reading file " + filePath);
+    try {
+      FileResource file = new FileResource();
+
+      if (page == null)
+        page = 0L;
+
+      if (filePath.startsWith(FAKE_FILE)) {
+        if (page > 1)
+          throw new IllegalArgumentException("There's only one page in fake files");
+
+        String encodedContent = filePath.substring(FAKE_FILE.length());
+        String content = new String(Base64.decodeBase64(encodedContent));
+
+        fillFakeFileObject(filePath, file, content);
+      } else if (filePath.startsWith(JSON_PATH_FILE)) {
+        if (page > 1)
+          throw new IllegalArgumentException("There's only one page in fake files");
+
+        String content = getJsonPathContentByUrl(filePath);
+        fillFakeFileObject(filePath, file, content);
+      } else  {
+
+        filePath = sanitizeFilePath(filePath);
+        FilePaginator paginator = new FilePaginator(filePath, getSharedObjectsFactory().getHdfsApi());
+
+        fillRealFileObject(filePath, page, file, paginator);
+      }
+
+      JSONObject object = new JSONObject();
+      object.put("file", file);
+      return Response.ok(object).status(200).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (FileNotFoundException ex) {
+      throw new NotFoundFormattedException(ex.getMessage(), ex);
+    } catch (IllegalArgumentException ex) {
+      throw new BadRequestFormattedException(ex.getMessage(), ex);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  protected String getJsonPathContentByUrl(String filePath) throws IOException {
+    URL url = new URL(filePath.substring(JSON_PATH_FILE.length()));
+
+    InputStream responseInputStream = context.getURLStreamProvider().readFrom(url.toString(), "GET",
+        (String)null, new HashMap<String, String>());
+    String response = IOUtils.toString(responseInputStream);
+
+    for (String ref : url.getRef().split("!")) {
+      response = JsonPath.read(response, ref);
+    }
+    return response;
+  }
+
+  public void fillRealFileObject(String filePath, Long page, FileResource file, FilePaginator paginator) throws IOException, InterruptedException {
+    file.setFilePath(filePath);
+    file.setFileContent(paginator.readPage(page));
+    file.setHasNext(paginator.pageCount() > page + 1);
+    file.setPage(page);
+    file.setPageCount(paginator.pageCount());
+  }
+
+  public void fillFakeFileObject(String filePath, FileResource file, String content) {
+    file.setFilePath(filePath);
+    file.setFileContent(content);
+    file.setHasNext(false);
+    file.setPage(0);
+    file.setPageCount(1);
+  }
+
+  /**
+   * Delete single item
+   */
+  @DELETE
+  @Path("{filePath:.*}")
+  public Response deleteFile(@PathParam("filePath") String filePath) throws IOException, InterruptedException {
+    try {
+      filePath = sanitizeFilePath(filePath);
+      LOG.debug("Deleting file " + filePath);
+      if (getSharedObjectsFactory().getHdfsApi().delete(filePath, false)) {
+        return Response.status(204).build();
+      }
+      throw new NotFoundFormattedException("FileSystem.delete returned false", null);
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Update item
+   */
+  @PUT
+  @Path("{filePath:.*}")
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response updateFile(FileResourceRequest request,
+                             @PathParam("filePath") String filePath) throws IOException, InterruptedException {
+    try {
+      filePath = sanitizeFilePath(filePath);
+      LOG.debug("Rewriting file " + filePath);
+      FSDataOutputStream output = getSharedObjectsFactory().getHdfsApi().create(filePath, true);
+      output.writeBytes(request.file.getFileContent());
+      output.close();
+      return Response.status(204).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Create script
+   */
+  @POST
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response createFile(FileResourceRequest request,
+                             @Context HttpServletResponse response, @Context UriInfo ui)
+      throws IOException, InterruptedException {
+    try {
+      LOG.debug("Creating file " + request.file.getFilePath());
+      try {
+        FSDataOutputStream output = getSharedObjectsFactory().getHdfsApi().create(request.file.getFilePath(), false);
+        if (request.file.getFileContent() != null) {
+          output.writeBytes(request.file.getFileContent());
+        }
+        output.close();
+      } catch (FileAlreadyExistsException ex) {
+        throw new ServiceFormattedException("F020 File already exists", ex, 400);
+      }
+      response.setHeader("Location",
+          String.format("%s/%s", ui.getAbsolutePath().toString(), request.file.getFilePath()));
+      return Response.status(204).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Checks connection to HDFS
+   * @param context View Context
+   */
+  public static void hdfsSmokeTest(ViewContext context) {
+    try {
+      HdfsApi api = HdfsUtil.connectToHDFSApi(context);
+      api.getStatus();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Wrapper object for json mapping
+   */
+  public static class FileResourceRequest {
+    public FileResource file;
+  }
+
+  private String sanitizeFilePath(String filePath){
+    if (!filePath.startsWith("/") && !filePath.startsWith(".")) {
+      filePath = "/" + filePath;  // some servers strip double slashes in URL
+    }
+    return filePath;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/Aggregator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/Aggregator.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/Aggregator.java
new file mode 100644
index 0000000..e7553dd
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/Aggregator.java
@@ -0,0 +1,231 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view.hive2.resources.jobs;
+
+import org.apache.ambari.view.hive2.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive2.persistence.utils.Indexed;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.resources.IResourceManager;
+import org.apache.ambari.view.hive2.resources.files.FileService;
+import org.apache.ambari.view.hive2.resources.jobs.atsJobs.HiveQueryId;
+import org.apache.ambari.view.hive2.resources.jobs.atsJobs.IATSParser;
+import org.apache.ambari.view.hive2.resources.jobs.atsJobs.TezDagId;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.Job;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobImpl;
+import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.codec.binary.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * View Jobs and ATS Jobs aggregator.
+ * There are 4 options:
+ * 1) ATS ExecuteJob without operationId
+ *    *Meaning*: executed outside of HS2
+ *    - ExecuteJob info only from ATS
+ * 2) ATS ExecuteJob with operationId
+ *    a) Hive View ExecuteJob with same operationId is not present
+ *        *Meaning*: executed with HS2
+ *      - ExecuteJob info only from ATS
+ *    b) Hive View ExecuteJob with operationId is present (need to merge)
+ *        *Meaning*: executed with HS2 through Hive View
+ *      - ExecuteJob info merged from ATS and from Hive View DataStorage
+ * 3) ExecuteJob present only in Hive View, ATS does not have it
+ *   *Meaning*: executed through Hive View, but Hadoop ExecuteJob was not created
+ *   it can happen if user executes query without aggregation, like just "select * from TABLE"
+ *   - ExecuteJob info only from Hive View
+ */
+public class Aggregator {
+  protected final static Logger LOG =
+    LoggerFactory.getLogger(Aggregator.class);
+
+  private final IATSParser ats;
+  private IResourceManager<Job> viewJobResourceManager;
+
+  public Aggregator(IResourceManager<Job> jobResourceManager,
+                    IATSParser ats) {
+    this.viewJobResourceManager = jobResourceManager;
+    this.ats = ats;
+  }
+
+  public List<Job> readAll(String username) {
+    Set<String> addedOperationIds = new HashSet<>();
+
+    List<Job> allJobs = new LinkedList<>();
+    for (HiveQueryId atsHiveQuery : ats.getHiveQueryIdsList(username)) {
+
+      TezDagId atsTezDag = getTezDagFromHiveQueryId(atsHiveQuery);
+
+      JobImpl atsJob;
+      if (hasOperationId(atsHiveQuery)) {
+        try {
+          Job viewJob = getJobByOperationId(urlSafeBase64ToHexString(atsHiveQuery.operationId));
+          saveJobInfoIfNeeded(atsHiveQuery, atsTezDag, viewJob);
+
+          atsJob = mergeAtsJobWithViewJob(atsHiveQuery, atsTezDag, viewJob);
+        } catch (ItemNotFound itemNotFound) {
+          // Executed from HS2, but outside of Hive View
+          atsJob = atsOnlyJob(atsHiveQuery, atsTezDag);
+        }
+      } else {
+        atsJob = atsOnlyJob(atsHiveQuery, atsTezDag);
+      }
+      allJobs.add(atsJob);
+
+      addedOperationIds.add(atsHiveQuery.operationId);
+    }
+
+    return allJobs;
+  }
+
+  public Job readATSJob(Job viewJob) throws ItemNotFound {
+
+    if (viewJob.getStatus().equals(Job.JOB_STATE_INITIALIZED) || viewJob.getStatus().equals(Job.JOB_STATE_UNKNOWN))
+      return viewJob;
+
+    String hexGuid = viewJob.getGuid();
+
+
+    HiveQueryId atsHiveQuery = ats.getHiveQueryIdByOperationId(hexGuid);
+
+    TezDagId atsTezDag = getTezDagFromHiveQueryId(atsHiveQuery);
+
+    saveJobInfoIfNeeded(atsHiveQuery, atsTezDag, viewJob);
+    return mergeAtsJobWithViewJob(atsHiveQuery, atsTezDag, viewJob);
+  }
+
+  private TezDagId getTezDagFromHiveQueryId(HiveQueryId atsHiveQuery) {
+    TezDagId atsTezDag;
+    if (atsHiveQuery.version >= HiveQueryId.ATS_15_RESPONSE_VERSION) {
+      atsTezDag = ats.getTezDAGByEntity(atsHiveQuery.entity);
+    } else if (atsHiveQuery.dagNames != null && atsHiveQuery.dagNames.size() > 0) {
+      String dagName = atsHiveQuery.dagNames.get(0);
+
+      atsTezDag = ats.getTezDAGByName(dagName);
+    } else {
+      atsTezDag = new TezDagId();
+    }
+    return atsTezDag;
+  }
+
+  protected boolean hasOperationId(HiveQueryId atsHiveQuery) {
+    return atsHiveQuery.operationId != null;
+  }
+
+  protected JobImpl mergeAtsJobWithViewJob(HiveQueryId atsHiveQuery, TezDagId atsTezDag, Job viewJob) {
+    JobImpl atsJob;
+    try {
+      atsJob = new JobImpl(PropertyUtils.describe(viewJob));
+    } catch (IllegalAccessException e) {
+      LOG.error("Can't instantiate JobImpl", e);
+      return null;
+    } catch (InvocationTargetException e) {
+      LOG.error("Can't instantiate JobImpl", e);
+      return null;
+    } catch (NoSuchMethodException e) {
+      LOG.error("Can't instantiate JobImpl", e);
+      return null;
+    }
+    fillAtsJobFields(atsJob, atsHiveQuery, atsTezDag);
+    return atsJob;
+  }
+
+  protected void saveJobInfoIfNeeded(HiveQueryId hiveQueryId, TezDagId tezDagId, Job viewJob) throws ItemNotFound {
+    if (viewJob.getDagName() == null || viewJob.getDagName().isEmpty()) {
+      if (hiveQueryId.dagNames != null && hiveQueryId.dagNames.size() > 0) {
+        viewJob.setDagName(hiveQueryId.dagNames.get(0));
+        viewJobResourceManager.update(viewJob, viewJob.getId());
+      }
+    }
+    if (tezDagId.status != null && (tezDagId.status.compareToIgnoreCase(Job.JOB_STATE_UNKNOWN) != 0) &&
+      !viewJob.getStatus().equalsIgnoreCase(tezDagId.status)) {
+      viewJob.setDagId(tezDagId.entity);
+      viewJob.setApplicationId(tezDagId.applicationId);
+      if (!(viewJob.getStatus().equalsIgnoreCase(Job.JOB_STATE_FINISHED)
+        || (viewJob.getStatus().equalsIgnoreCase(Job.JOB_STATE_ERROR))
+        || viewJob.getStatus().equalsIgnoreCase(Job.JOB_STATE_CANCELED))) {
+        viewJob.setStatus(tezDagId.status);
+      }
+      viewJobResourceManager.update(viewJob, viewJob.getId());
+    }
+  }
+
+  protected JobImpl atsOnlyJob(HiveQueryId atsHiveQuery, TezDagId atsTezDag) {
+    JobImpl atsJob = new JobImpl();
+    atsJob.setId(atsHiveQuery.entity);
+    fillAtsJobFields(atsJob, atsHiveQuery, atsTezDag);
+
+    String query = atsHiveQuery.query;
+    atsJob.setTitle(query.substring(0, (query.length() > 42) ? 42 : query.length()));
+
+    atsJob.setQueryFile(FileService.JSON_PATH_FILE + atsHiveQuery.url + "#otherinfo.QUERY!queryText");
+    return atsJob;
+  }
+
+  protected JobImpl fillAtsJobFields(JobImpl atsJob, HiveQueryId atsHiveQuery, TezDagId atsTezDag) {
+    atsJob.setApplicationId(atsTezDag.applicationId);
+
+    if (atsHiveQuery.dagNames != null && atsHiveQuery.dagNames.size() > 0)
+      atsJob.setDagName(atsHiveQuery.dagNames.get(0));
+    atsJob.setDagId(atsTezDag.entity);
+    if (atsTezDag.status != null && !atsTezDag.status.equals(TezDagId.STATUS_UNKNOWN))
+      atsJob.setStatus(atsTezDag.status);
+    if (atsHiveQuery.starttime != 0)
+      atsJob.setDateSubmitted(atsHiveQuery.starttime);
+    atsJob.setDuration(atsHiveQuery.duration);
+    return atsJob;
+  }
+
+  protected Job getJobByOperationId(final String opId) throws ItemNotFound {
+    List<Job> operationHandles = viewJobResourceManager.readAll(new FilteringStrategy() {
+      @Override
+      public boolean isConform(Indexed item) {
+        Job opHandle = (Job) item;
+        return opHandle.getGuid().equals(opId);
+      }
+
+      @Override
+      public String whereStatement() {
+        return "guid='" + opId + "'";
+      }
+    });
+
+    if (operationHandles.size() != 1)
+      throw new ItemNotFound();
+
+    return viewJobResourceManager.read(operationHandles.get(0).getId());
+  }
+
+  protected static String urlSafeBase64ToHexString(String urlsafeBase64) {
+    byte[] decoded = Base64.decodeBase64(urlsafeBase64);
+
+    StringBuilder sb = new StringBuilder();
+    for (byte b : decoded) {
+      sb.append(String.format("%02x", b));
+    }
+    return sb.toString();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobResourceProvider.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobResourceProvider.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobResourceProvider.java
new file mode 100644
index 0000000..28573b3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobResourceProvider.java
@@ -0,0 +1,117 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs;
+
+import org.apache.ambari.view.*;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.*;
+import org.apache.ambari.view.hive2.utils.SharedObjectsFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Resource provider for job
+ */
+public class JobResourceProvider implements ResourceProvider<Job> {
+  @Inject
+  ViewContext context;
+
+  protected JobResourceManager resourceManager = null;
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(JobResourceProvider.class);
+
+  protected synchronized JobResourceManager getResourceManager() {
+    if (resourceManager == null) {
+      resourceManager = new JobResourceManager(new SharedObjectsFactory(context), context);
+    }
+    return resourceManager;
+  }
+
+  @Override
+  public Job getResource(String resourceId, Set<String> properties) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      return getResourceManager().read(resourceId);
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+  }
+
+  @Override
+  public Set<Job> getResources(ReadRequest readRequest) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    if (context == null) {
+      return new HashSet<Job>();
+    }
+    return new HashSet<Job>(getResourceManager().readAll(
+        new OnlyOwnersFilteringStrategy(this.context.getUsername())));
+  }
+
+  @Override
+  public void createResource(String s, Map<String, Object> stringObjectMap) throws SystemException, ResourceAlreadyExistsException, NoSuchResourceException, UnsupportedPropertyException {
+    Job item = null;
+    try {
+      item = new JobImpl(stringObjectMap);
+    } catch (InvocationTargetException e) {
+      throw new SystemException("error on creating resource", e);
+    } catch (IllegalAccessException e) {
+      throw new SystemException("error on creating resource", e);
+    }
+    getResourceManager().create(item);
+    JobController jobController = new SharedObjectsFactory(context).getJobControllerFactory().createControllerForJob(item);
+    try {
+      jobController.submit();
+    } catch (Throwable throwable) {
+      throw new SystemException("error on creating resource", throwable);
+    }
+  }
+
+  @Override
+  public boolean updateResource(String resourceId, Map<String, Object> stringObjectMap) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    Job item = null;
+    try {
+      item = new JobImpl(stringObjectMap);
+    } catch (InvocationTargetException e) {
+      throw new SystemException("error on updating resource", e);
+    } catch (IllegalAccessException e) {
+      throw new SystemException("error on updating resource", e);
+    }
+    try {
+      getResourceManager().update(item, resourceId);
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+
+  @Override
+  public boolean deleteResource(String resourceId) throws SystemException, NoSuchResourceException, UnsupportedPropertyException {
+    try {
+      getResourceManager().delete(resourceId);
+    } catch (ItemNotFound itemNotFound) {
+      throw new NoSuchResourceException(resourceId);
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobService.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobService.java
new file mode 100644
index 0000000..4fa7f2a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobService.java
@@ -0,0 +1,612 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs;
+
+import com.beust.jcommander.internal.Lists;
+import com.google.common.base.Optional;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.hive2.BaseService;
+import org.apache.ambari.view.hive2.actor.message.job.AsyncExecutionFailed;
+import org.apache.ambari.view.hive2.backgroundjobs.BackgroundJobController;
+import org.apache.ambari.view.hive2.client.AsyncJobRunner;
+import org.apache.ambari.view.hive2.client.AsyncJobRunnerImpl;
+import org.apache.ambari.view.hive2.client.ColumnDescription;
+import org.apache.ambari.view.hive2.client.Cursor;
+import org.apache.ambari.view.hive2.client.EmptyCursor;
+import org.apache.ambari.view.hive2.client.HiveClientException;
+import org.apache.ambari.view.hive2.client.NonPersistentCursor;
+import org.apache.ambari.view.hive2.client.Row;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.resources.jobs.atsJobs.IATSParser;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.Job;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobController;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobImpl;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobResourceManager;
+import org.apache.ambari.view.hive2.utils.MisconfigurationFormattedException;
+import org.apache.ambari.view.hive2.utils.NotFoundFormattedException;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.apache.ambari.view.hive2.utils.SharedObjectsFactory;
+import org.apache.ambari.view.hive2.ConnectionSystem;
+import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletResponse;
+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.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import javax.ws.rs.core.UriInfo;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+/**
+ * Servlet for queries
+ * API:
+ * GET /:id
+ *      read job
+ * POST /
+ *      create new job
+ *      Required: title, queryFile
+ * GET /
+ *      get all Jobs of current user
+ */
+public class JobService extends BaseService {
+  @Inject
+  ViewResourceHandler handler;
+
+  private JobResourceManager resourceManager;
+
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(JobService.class);
+  private Aggregator aggregator;
+
+  protected synchronized JobResourceManager getResourceManager() {
+    if (resourceManager == null) {
+      SharedObjectsFactory connectionsFactory = getSharedObjectsFactory();
+      resourceManager = new JobResourceManager(connectionsFactory, context);
+    }
+    return resourceManager;
+  }
+
+
+  protected Aggregator getAggregator() {
+    if (aggregator == null) {
+      IATSParser atsParser = getSharedObjectsFactory().getATSParser();
+      aggregator = new Aggregator(getResourceManager(), atsParser);
+    }
+    return aggregator;
+  }
+
+  protected void setAggregator(Aggregator aggregator) {
+    this.aggregator = aggregator;
+  }
+
+  /**
+   * Get single item
+   */
+  @GET
+  @Path("{jobId}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getOne(@PathParam("jobId") String jobId) {
+    try {
+      JobController jobController = getResourceManager().readController(jobId);
+
+      Job job = jobController.getJob();
+      if(job.getStatus().equals(Job.JOB_STATE_ERROR)){
+        ConnectionSystem system = ConnectionSystem.getInstance();
+        final AsyncJobRunner asyncJobRunner = new AsyncJobRunnerImpl(context, system.getOperationController(context), system.getActorSystem());
+        Optional<AsyncExecutionFailed> error = asyncJobRunner.getError(jobId, context.getUsername());
+        if(error.isPresent()){
+          throw new Exception(error.get().getError());
+        }
+      }
+
+      JSONObject jsonJob = jsonObjectFromJob(jobController);
+      return Response.ok(jsonJob).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  private JSONObject jsonObjectFromJob(JobController jobController) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
+    Job hiveJob = jobController.getJobPOJO();
+
+    Job mergedJob;
+    try {
+      mergedJob = getAggregator().readATSJob(hiveJob);
+    } catch (ItemNotFound itemNotFound) {
+      throw new ServiceFormattedException("E010 ExecuteJob not found", itemNotFound);
+    }
+    Map createdJobMap = PropertyUtils.describe(mergedJob);
+    createdJobMap.remove("class"); // no need to show Bean class on client
+
+    JSONObject jobJson = new JSONObject();
+    jobJson.put("job", createdJobMap);
+    return jobJson;
+  }
+
+  /**
+   * Get job results in csv format
+   */
+  @GET
+  @Path("{jobId}/results/csv")
+  @Produces("text/csv")
+  public Response getResultsCSV(@PathParam("jobId") String jobId,
+                                @Context HttpServletResponse response,
+                                @QueryParam("fileName") String fileName,
+                                @QueryParam("columns") final String requestedColumns) {
+    try {
+
+      final String username = context.getUsername();
+
+      ConnectionSystem system = ConnectionSystem.getInstance();
+      final AsyncJobRunner asyncJobRunner = new AsyncJobRunnerImpl(context, system.getOperationController(context), system.getActorSystem());
+
+      Optional<NonPersistentCursor> cursorOptional = asyncJobRunner.resetAndGetCursor(jobId, username);
+
+      if(!cursorOptional.isPresent()){
+        throw new Exception("Download failed");
+      }
+
+      final NonPersistentCursor resultSet = cursorOptional.get();
+
+
+      StreamingOutput stream = new StreamingOutput() {
+        @Override
+        public void write(OutputStream os) throws IOException, WebApplicationException {
+          Writer writer = new BufferedWriter(new OutputStreamWriter(os));
+          CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT);
+          try {
+
+            List<ColumnDescription> descriptions = resultSet.getDescriptions();
+            List<String> headers = Lists.newArrayList();
+            for (ColumnDescription description : descriptions) {
+              headers.add(description.getName());
+            }
+
+            csvPrinter.printRecord(headers.toArray());
+
+            while (resultSet.hasNext()) {
+              csvPrinter.printRecord(resultSet.next().getRow());
+              writer.flush();
+            }
+          } finally {
+            writer.close();
+          }
+        }
+      };
+
+      if (fileName == null || fileName.isEmpty()) {
+        fileName = "results.csv";
+      }
+
+      return Response.ok(stream).
+          header("Content-Disposition", String.format("attachment; filename=\"%s\"", fileName)).
+          build();
+
+
+    } catch (WebApplicationException ex) {
+      throw ex;
+    }  catch (Throwable ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Get job results in csv format
+   */
+  @GET
+  @Path("{jobId}/results/csv/saveToHDFS")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getResultsToHDFS(@PathParam("jobId") String jobId,
+                                   @QueryParam("commence") String commence,
+                                   @QueryParam("file") final String targetFile,
+                                   @QueryParam("stop") final String stop,
+                                   @QueryParam("columns") final String requestedColumns,
+                                   @Context HttpServletResponse response) {
+    try {
+
+      final JobController jobController = getResourceManager().readController(jobId);
+      final String username = context.getUsername();
+
+      String backgroundJobId = "csv" + String.valueOf(jobController.getJob().getId());
+      if (commence != null && commence.equals("true")) {
+        if (targetFile == null)
+          throw new MisconfigurationFormattedException("targetFile should not be empty");
+
+        ConnectionSystem system = ConnectionSystem.getInstance();
+        final AsyncJobRunner asyncJobRunner = new AsyncJobRunnerImpl(context, system.getOperationController(context), system.getActorSystem());
+
+        Optional<NonPersistentCursor> cursorOptional = asyncJobRunner.resetAndGetCursor(jobId, username);
+
+        if(!cursorOptional.isPresent()){
+          throw new Exception("Download failed");
+        }
+
+        final NonPersistentCursor resultSet = cursorOptional.get();
+
+        BackgroundJobController.getInstance(context).startJob(String.valueOf(backgroundJobId), new Runnable() {
+          @Override
+          public void run() {
+
+            try {
+
+              FSDataOutputStream stream = getSharedObjectsFactory().getHdfsApi().create(targetFile, true);
+              Writer writer = new BufferedWriter(new OutputStreamWriter(stream));
+              CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT);
+              try {
+                while (resultSet.hasNext() && !Thread.currentThread().isInterrupted()) {
+                  csvPrinter.printRecord(resultSet.next().getRow());
+                  writer.flush();
+                }
+              } finally {
+                writer.close();
+              }
+              stream.close();
+
+            } catch (IOException e) {
+              throw new ServiceFormattedException("F010 Could not write CSV to HDFS for job#" + jobController.getJob().getId(), e);
+            } catch (InterruptedException e) {
+              throw new ServiceFormattedException("F010 Could not write CSV to HDFS for job#" + jobController.getJob().getId(), e);
+            }
+          }
+        });
+      }
+
+      if (stop != null && stop.equals("true")) {
+        BackgroundJobController.getInstance(context).interrupt(backgroundJobId);
+      }
+
+      JSONObject object = new JSONObject();
+      object.put("stopped", BackgroundJobController.getInstance(context).isInterrupted(backgroundJobId));
+      object.put("jobId", jobController.getJob().getId());
+      object.put("backgroundJobId", backgroundJobId);
+      object.put("operationType", "CSV2HDFS");
+      object.put("status", BackgroundJobController.getInstance(context).state(backgroundJobId).toString());
+
+      return Response.ok(object).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+
+  @Path("{jobId}/status")
+  @GET
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response fetchJobStatus(@PathParam("jobId") String jobId) throws ItemNotFound, HiveClientException, NoOperationStatusSetException {
+    JobController jobController = getResourceManager().readController(jobId);
+    Job job = jobController.getJob();
+    String jobStatus = job.getStatus();
+
+
+    LOG.info("jobStatus : {} for jobId : {}",jobStatus, jobId);
+
+    JSONObject jsonObject = new JSONObject();
+    jsonObject.put("jobStatus", jobStatus);
+    jsonObject.put("jobId", jobId);
+
+    return Response.ok(jsonObject).build();
+  }
+
+  /**
+   * Get next results page
+   */
+  @GET
+  @Path("{jobId}/results")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getResults(@PathParam("jobId") final String jobId,
+                             @QueryParam("first") final String fromBeginning,
+                             @QueryParam("count") Integer count,
+                             @QueryParam("searchId") String searchId,
+                             @QueryParam("format") String format,
+                             @QueryParam("columns") final String requestedColumns) {
+    try {
+
+      final String username = context.getUsername();
+
+      ConnectionSystem system = ConnectionSystem.getInstance();
+      final AsyncJobRunner asyncJobRunner = new AsyncJobRunnerImpl(context, system.getOperationController(context), system.getActorSystem());
+
+      return ResultsPaginationController.getInstance(context)
+              .request(jobId, searchId, true, fromBeginning, count, format,requestedColumns,
+                      new Callable<Cursor< Row, ColumnDescription >>() {
+                        @Override
+                        public Cursor call() throws Exception {
+                          Optional<NonPersistentCursor> cursor;
+                          if(fromBeginning != null && fromBeginning.equals("true")){
+                            cursor = asyncJobRunner.resetAndGetCursor(jobId, username);
+                          }
+                          else {
+                            cursor = asyncJobRunner.getCursor(jobId, username);
+                          }
+                          if(cursor.isPresent())
+                          return cursor.get();
+                          else
+                            return new EmptyCursor();
+                        }
+                      }).build();
+
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Renew expiration time for results
+   */
+  @GET
+  @Path("{jobId}/results/keepAlive")
+  public Response keepAliveResults(@PathParam("jobId") String jobId,
+                             @QueryParam("first") String fromBeginning,
+                             @QueryParam("count") Integer count) {
+    try {
+      if (!ResultsPaginationController.getInstance(context).keepAlive(jobId, ResultsPaginationController.DEFAULT_SEARCH_ID)) {
+        throw new NotFoundFormattedException("Results already expired", null);
+      }
+      return Response.ok().build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Get progress info
+   */
+  @GET
+  @Path("{jobId}/progress")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getProgress(@PathParam("jobId") String jobId) {
+    try {
+      final JobController jobController = getResourceManager().readController(jobId);
+
+      ProgressRetriever.Progress progress = new ProgressRetriever(jobController.getJob(), getSharedObjectsFactory()).
+          getProgress();
+
+      return Response.ok(progress).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Delete single item
+   */
+  @DELETE
+  @Path("{id}")
+  public Response delete(@PathParam("id") String id,
+                         @QueryParam("remove") final String remove) {
+    try {
+      JobController jobController;
+      try {
+        jobController = getResourceManager().readController(id);
+      } catch (ItemNotFound itemNotFound) {
+        throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+      }
+      jobController.cancel();
+      if (remove != null && remove.compareTo("true") == 0) {
+        getResourceManager().delete(id);
+      }
+      return Response.status(204).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Get all Jobs
+   */
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response getList() {
+    try {
+      LOG.debug("Getting all job");
+      List<Job> allJobs = getAggregator().readAll(context.getUsername());
+      for(Job job : allJobs) {
+        job.setSessionTag(null);
+      }
+
+      JSONObject object = new JSONObject();
+      object.put("jobs", allJobs);
+      return Response.ok(object).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Create job
+   */
+  @POST
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response create(JobRequest request, @Context HttpServletResponse response,
+                         @Context UriInfo ui) {
+    try {
+      Map jobInfo = PropertyUtils.describe(request.job);
+      Job job = new JobImpl(jobInfo);
+
+
+      getResourceManager().create(job);
+
+      JobController createdJobController = getResourceManager().readController(job.getId());
+      createdJobController.submit();
+      getResourceManager().saveIfModified(createdJobController);
+
+      response.setHeader("Location",
+          String.format("%s/%s", ui.getAbsolutePath().toString(), job.getId()));
+
+      JSONObject jobObject = jsonObjectFromJob(createdJobController);
+
+      return Response.ok(jobObject).status(201).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (ItemNotFound itemNotFound) {
+      throw new NotFoundFormattedException(itemNotFound.getMessage(), itemNotFound);
+    } catch (Throwable ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Set password and connect to Hive
+   */
+  @POST
+  @Path("auth")
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response setupPassword(AuthRequest request) {
+    try {
+      /*HiveAuthCredentials authCredentials = new HiveAuthCredentials();
+      authCredentials.setPassword(request.password);
+      new UserLocalHiveAuthCredentials().set(authCredentials, context);*/
+
+      //connectionLocal.remove(context);  // force reconnect on next get
+      //connectionLocal.get(context);
+      return Response.ok().status(200).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Remove connection credentials
+   */
+  @DELETE
+  @Path("auth")
+  public Response removePassword() {
+    try {
+      //new UserLocalHiveAuthCredentials().remove(context);
+      //connectionLocal.remove(context);  // force reconnect on next get
+      return Response.ok().status(200).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+
+  /**
+   * Invalidate session
+   */
+  @DELETE
+  @Path("sessions/{sessionTag}")
+  public Response invalidateSession(@PathParam("sessionTag") String sessionTag) {
+    try {
+      //Connection connection = connectionLocal.get(context);
+      //connection.invalidateSessionByTag(sessionTag);
+      return Response.ok().build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Session status
+   */
+  @GET
+  @Path("sessions/{sessionTag}")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response sessionStatus(@PathParam("sessionTag") String sessionTag) {
+    try {
+      //Connection connection = connectionLocal.get(context);
+
+      JSONObject session = new JSONObject();
+      session.put("sessionTag", sessionTag);
+      try {
+        //connection.getSessionByTag(sessionTag);
+        session.put("actual", true);
+      } catch (Exception /*HiveClientException*/ ex) {
+        session.put("actual", false);
+      }
+
+      //TODO: New implementation
+
+      JSONObject status = new JSONObject();
+      status.put("session", session);
+      return Response.ok(status).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+
+  /**
+   * Wrapper object for json mapping
+   */
+  public static class JobRequest {
+    public JobImpl job;
+  }
+
+  /**
+   * Wrapper for authentication json mapping
+   */
+  public static class AuthRequest {
+    public String password;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ModifyNotificationDelegate.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ModifyNotificationDelegate.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ModifyNotificationDelegate.java
new file mode 100644
index 0000000..aad346b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ModifyNotificationDelegate.java
@@ -0,0 +1,23 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs;
+
+public interface ModifyNotificationDelegate {
+  boolean onModification(Object object);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ModifyNotificationInvocationHandler.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ModifyNotificationInvocationHandler.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ModifyNotificationInvocationHandler.java
new file mode 100644
index 0000000..e4d6739
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ModifyNotificationInvocationHandler.java
@@ -0,0 +1,40 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+public class ModifyNotificationInvocationHandler implements InvocationHandler {
+  private Object proxied;
+  private ModifyNotificationDelegate modifyDelegate;
+
+  public ModifyNotificationInvocationHandler(Object proxied, ModifyNotificationDelegate delegate) {
+    this.proxied = proxied;
+    this.modifyDelegate = delegate;
+  }
+
+  @Override
+  public Object invoke(Object o, Method method, Object[] args) throws Throwable {
+    if (method.getName().startsWith("set")) {
+      modifyDelegate.onModification(proxied);
+    }
+    return method.invoke(proxied, args);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/NoOperationStatusSetException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/NoOperationStatusSetException.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/NoOperationStatusSetException.java
new file mode 100644
index 0000000..1b92878
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/NoOperationStatusSetException.java
@@ -0,0 +1,23 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs;
+
+
+public class NoOperationStatusSetException extends Exception {
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ProgressRetriever.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ProgressRetriever.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ProgressRetriever.java
new file mode 100644
index 0000000..8f9caa4
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ProgressRetriever.java
@@ -0,0 +1,66 @@
+/**
+ * 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.ambari.view.hive2.resources.jobs;
+
+import org.apache.ambari.view.hive2.resources.jobs.atsJobs.TezVertexId;
+import org.apache.ambari.view.hive2.resources.jobs.rm.RMParser;
+import org.apache.ambari.view.hive2.resources.jobs.viewJobs.Job;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.apache.ambari.view.hive2.utils.SharedObjectsFactory;
+
+import java.util.List;
+
+public class ProgressRetriever {
+  private final Progress progress;
+  private final Job job;
+  private final SharedObjectsFactory sharedObjects;
+
+  public ProgressRetriever(Job job, SharedObjectsFactory sharedObjects) {
+    this.job = job;
+    this.sharedObjects = sharedObjects;
+
+    this.progress = new Progress();
+  }
+
+  public Progress getProgress() {
+    jobCheck();
+
+    progress.dagProgress = sharedObjects.getRMParser().getDAGProgress(
+        job.getApplicationId(), job.getDagId());
+
+    List<TezVertexId> vertices = sharedObjects.getATSParser().getVerticesForDAGId(job.getDagId());
+    progress.vertexProgresses = sharedObjects.getRMParser().getDAGVerticesProgress(job.getApplicationId(), job.getDagId(), vertices);
+
+    return progress;
+  }
+
+  public void jobCheck() {
+    if (job.getApplicationId() == null || job.getApplicationId().isEmpty()) {
+      throw new ServiceFormattedException("E070 ApplicationId is not defined yet");
+    }
+    if (job.getDagId() == null || job.getDagId().isEmpty()) {
+      throw new ServiceFormattedException("E080 DagID is not defined yet");
+    }
+  }
+
+  public static class Progress {
+    public Double dagProgress;
+    public List<RMParser.VertexProgress> vertexProgresses;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ResultsPaginationController.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ResultsPaginationController.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ResultsPaginationController.java
new file mode 100644
index 0000000..6131d03
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/ResultsPaginationController.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.resources.jobs;
+
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.client.ColumnDescription;
+import org.apache.ambari.view.hive2.client.Cursor;
+import org.apache.ambari.view.hive2.client.HiveClientException;
+import org.apache.ambari.view.hive2.client.Row;
+import org.apache.ambari.view.hive2.utils.BadRequestFormattedException;
+import org.apache.ambari.view.hive2.utils.HiveClientFormattedException;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.apache.commons.collections4.map.PassiveExpiringMap;
+import org.apache.hadoop.hbase.util.Strings;
+
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+/**
+ * Results Pagination Controller
+ * Persists cursors for result sets
+ */
+public class ResultsPaginationController {
+  public static final String DEFAULT_SEARCH_ID = "default";
+  private static Map<String, ResultsPaginationController> viewSingletonObjects = new HashMap<String, ResultsPaginationController>();
+  public static ResultsPaginationController getInstance(ViewContext context) {
+    if (!viewSingletonObjects.containsKey(context.getInstanceName()))
+      viewSingletonObjects.put(context.getInstanceName(), new ResultsPaginationController());
+    return viewSingletonObjects.get(context.getInstanceName());
+  }
+
+  public ResultsPaginationController() {
+  }
+
+  private static final long EXPIRING_TIME = 10*60*1000;  // 10 minutes
+  private static final int DEFAULT_FETCH_COUNT = 50;
+  private Map<String, Cursor<Row, ColumnDescription>> resultsCache;
+
+  public static class CustomTimeToLiveExpirationPolicy extends PassiveExpiringMap.ConstantTimeToLiveExpirationPolicy<String, Cursor<Row, ColumnDescription>> {
+    public CustomTimeToLiveExpirationPolicy(long timeToLiveMillis) {
+      super(timeToLiveMillis);
+    }
+
+    @Override
+    public long expirationTime(String key, Cursor<Row, ColumnDescription> value) {
+      if (key.startsWith("$")) {
+        return -1;  //never expire
+      }
+      return super.expirationTime(key, value);
+    }
+  }
+
+  private Map<String, Cursor<Row, ColumnDescription>> getResultsCache() {
+    if (resultsCache == null) {
+      PassiveExpiringMap<String, Cursor<Row, ColumnDescription>> resultsCacheExpiringMap =
+          new PassiveExpiringMap<>(new CustomTimeToLiveExpirationPolicy(EXPIRING_TIME));
+      resultsCache = Collections.synchronizedMap(resultsCacheExpiringMap);
+    }
+    return resultsCache;
+  }
+
+  /**
+   * Renew timer of cache entry.
+   * @param key name/id of results request
+   * @return false if entry not found; true if renew was ok
+   */
+  public boolean keepAlive(String key, String searchId) {
+    if (searchId == null)
+      searchId = DEFAULT_SEARCH_ID;
+    String effectiveKey = key + "?" + searchId;
+    if (!getResultsCache().containsKey(effectiveKey)) {
+      return false;
+    }
+    Cursor cursor = getResultsCache().get(effectiveKey);
+    getResultsCache().put(effectiveKey, cursor);
+    cursor.keepAlive();
+    return true;
+  }
+
+  private Cursor<Row, ColumnDescription> getResultsSet(String key, Callable<Cursor<Row, ColumnDescription>> makeResultsSet) {
+    if (!getResultsCache().containsKey(key)) {
+      Cursor resultSet;
+      try {
+        resultSet = makeResultsSet.call();
+        if (resultSet.isResettable()) {
+          resultSet.reset();
+        }
+      } catch (HiveClientException ex) {
+        throw new HiveClientFormattedException(ex);
+      } catch (Exception ex) {
+        throw new ServiceFormattedException(ex.getMessage(), ex);
+      }
+      getResultsCache().put(key, resultSet);
+    }
+
+    return getResultsCache().get(key);
+  }
+
+  public Response.ResponseBuilder request(String key, String searchId, boolean canExpire, String fromBeginning, Integer count, String format, String requestedColumns, Callable<Cursor<Row, ColumnDescription>> makeResultsSet) throws HiveClientException {
+    if (searchId == null)
+      searchId = DEFAULT_SEARCH_ID;
+    key = key + "?" + searchId;
+    if (!canExpire)
+      key = "$" + key;
+    if (fromBeginning != null && fromBeginning.equals("true") && getResultsCache().containsKey(key)) {
+
+      getResultsCache().remove(key);
+    }
+
+    Cursor<Row, ColumnDescription> resultSet = getResultsSet(key, makeResultsSet);
+
+    if (count == null)
+      count = DEFAULT_FETCH_COUNT;
+
+    List<ColumnDescription> allschema = resultSet.getDescriptions();
+    List<Row> allRowEntries = FluentIterable.from(resultSet)
+      .limit(count).toList();
+
+    List<ColumnDescription> schema = allschema;
+
+    final Set<Integer> selectedColumns = getRequestedColumns(requestedColumns);
+    if (!selectedColumns.isEmpty()) {
+      schema = filter(allschema, selectedColumns);
+    }
+
+    List<Object[]> rows = FluentIterable.from(allRowEntries)
+      .transform(new Function<Row, Object[]>() {
+        @Override
+        public Object[] apply(Row input) {
+          if(!selectedColumns.isEmpty()) {
+            return filter(Lists.newArrayList(input.getRow()), selectedColumns).toArray();
+          } else {
+            return input.getRow();
+          }
+        }
+      }).toList();
+
+    int read = rows.size();
+    if(format != null && format.equalsIgnoreCase("d3")) {
+      List<Map<String,Object>> results = new ArrayList<>();
+      for(int i=0; i<rows.size(); i++) {
+        Object[] row = rows.get(i);
+        Map<String, Object> keyValue = new HashMap<>(row.length);
+        for(int j=0; j<row.length; j++) {
+          //Replace dots in schema with underscore
+          String schemaName = schema.get(j).getName();
+          keyValue.put(schemaName.replace('.','_'), row[j]);
+        }
+        results.add(keyValue);
+      }
+      return Response.ok(results);
+    } else {
+      ResultsResponse resultsResponse = new ResultsResponse();
+      resultsResponse.setSchema(schema);
+      resultsResponse.setRows(rows);
+      resultsResponse.setReadCount(read);
+      resultsResponse.setHasNext(resultSet.hasNext());
+      //      resultsResponse.setSize(resultSet.size());
+      resultsResponse.setOffset(resultSet.getOffset());
+      resultsResponse.setHasResults(true);
+      return Response.ok(resultsResponse);
+    }
+  }
+
+  private <T> List<T> filter(List<T> list, Set<Integer> selectedColumns) {
+    List<T> filtered = Lists.newArrayList();
+    for(int i: selectedColumns) {
+      filtered.add(list.get(i));
+    }
+
+    return filtered;
+  }
+
+  private Set<Integer> getRequestedColumns(String requestedColumns) {
+    if(Strings.isEmpty(requestedColumns)) {
+      return new HashSet<>();
+    }
+    Set<Integer> selectedColumns = Sets.newHashSet();
+    for (String columnRequested : requestedColumns.split(",")) {
+      try {
+        selectedColumns.add(Integer.parseInt(columnRequested));
+      } catch (NumberFormatException ex) {
+        throw new BadRequestFormattedException("Columns param should be comma-separated integers", ex);
+      }
+    }
+    return selectedColumns;
+  }
+
+  private static class ResultsResponse {
+    private List<ColumnDescription> schema;
+    private List<String[]> rows;
+    private int readCount;
+    private boolean hasNext;
+    private long offset;
+    private boolean hasResults;
+
+    public void setSchema(List<ColumnDescription> schema) {
+      this.schema = schema;
+    }
+
+    public List<ColumnDescription> getSchema() {
+      return schema;
+    }
+
+    public void setRows(List<Object[]> rows) {
+      if( null == rows ){
+        this.rows = null;
+      }
+      this.rows = new ArrayList<String[]>(rows.size());
+      for(Object[] row : rows ){
+        String[] strs = new String[row.length];
+        for( int colNum = 0 ; colNum < row.length ; colNum++ ){
+          String value = String.valueOf(row[colNum]);
+          if(row[colNum] != null && (value.isEmpty() || value.equalsIgnoreCase("null"))){
+            strs[colNum] = String.format("\"%s\"",value);
+          }else{
+            strs[colNum] = value;
+          }
+        }
+        this.rows.add(strs);
+      }
+    }
+
+    public List<String[]> getRows() {
+      return rows;
+    }
+
+    public void setReadCount(int readCount) {
+      this.readCount = readCount;
+    }
+
+    public void setHasNext(boolean hasNext) {
+      this.hasNext = hasNext;
+    }
+
+    public boolean isHasNext() {
+      return hasNext;
+    }
+
+    public long getOffset() {
+      return offset;
+    }
+
+    public void setOffset(long offset) {
+      this.offset = offset;
+    }
+
+    public boolean getHasResults() {
+      return hasResults;
+    }
+
+    public void setHasResults(boolean hasResults) {
+      this.hasResults = hasResults;
+    }
+  }
+}


[17/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ContextSupplier.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ContextSupplier.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ContextSupplier.java
new file mode 100644
index 0000000..e35885d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/ContextSupplier.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.internal;
+
+import org.apache.ambari.view.ViewContext;
+
+/**
+ * A class that can supply objects of same type.
+ * @param <T>
+ */
+public interface ContextSupplier<T> {
+  /**
+   * Retrieves an instance of appropriate type. The returned object could be a new instance
+   * or an exiting instance. No guarantee on that.
+   * @param context View Context to be used to create the instance
+   * @return instance of appropriateType
+   */
+  T get(ViewContext context);
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/DataStorageSupplier.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/DataStorageSupplier.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/DataStorageSupplier.java
new file mode 100644
index 0000000..f496d06
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/DataStorageSupplier.java
@@ -0,0 +1,42 @@
+/*
+ * 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.ambari.view.hive2.internal;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.DataStoreStorage;
+import org.apache.ambari.view.hive2.persistence.Storage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A supplier for data storage
+ * Duplicated to keep the API uniform
+ */
+public class DataStorageSupplier implements ContextSupplier<Storage> {
+
+  protected final Logger LOG =
+    LoggerFactory.getLogger(getClass());
+
+  @Override
+  public Storage get(ViewContext context) {
+    LOG.debug("Creating storage instance for Viewname: {}, Instance Name: {}", context.getViewName(), context.getInstanceName());
+    return new DataStoreStorage(context);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/DefaultSupplier.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/DefaultSupplier.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/DefaultSupplier.java
new file mode 100644
index 0000000..39c8594
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/DefaultSupplier.java
@@ -0,0 +1,62 @@
+/*
+ * 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.ambari.view.hive2.internal;
+
+import com.google.common.base.Supplier;
+
+import java.util.List;
+
+/**
+ * Create instances of classes
+ * for which no constructors have been specified
+ * @param <T>
+ */
+public class DefaultSupplier<T> implements Supplier<T>{
+
+    private Class<T> clazz;
+    T instance;
+
+    public DefaultSupplier(T instance) {
+        this.instance = instance;
+    }
+
+    public DefaultSupplier(Class<T> clazz) throws IllegalAccessException, InstantiationException {
+        this.clazz = clazz;
+    }
+
+    /**
+     * Get the instance
+     * @return
+     */
+    @Override
+    public T get() {
+        if(clazz != null){
+            try {
+                return clazz.newInstance();
+            } catch (InstantiationException e) {
+                e.printStackTrace();
+                return null;
+            } catch (IllegalAccessException e) {
+                return null;
+            }
+        } else {
+            return instance;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Either.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Either.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Either.java
new file mode 100644
index 0000000..52fb01e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Either.java
@@ -0,0 +1,78 @@
+/*
+ * 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.ambari.view.hive2.internal;
+
+import com.google.common.base.Optional;
+
+/**
+ * Simple implementation of a container class which can
+ * hold one of two values
+ *
+ * Callers should check if the value if left or right before
+ * trying to get the value
+ *
+ * @param <L> Left Value
+ * @param <R> Right value
+ */
+public class Either<L,R> {
+
+    private final Optional<L> left;
+    private final Optional<R> right;
+
+
+    public boolean isLeft(){
+       return left.isPresent() && !right.isPresent();
+    }
+
+    public boolean isRight(){
+        return !left.isPresent() && right.isPresent();
+    }
+
+    public L getLeft(){
+        return left.orNull();
+    }
+
+    public R getRight(){
+        return right.orNull();
+    }
+
+
+    private Either(Optional<L> left, Optional<R> right) {
+        this.left = left;
+        this.right = right;
+    }
+
+
+
+    public static <L,R> Either<L,R> left(L value) {
+        return new Either<>(Optional.of(value), Optional.<R>absent());
+    }
+
+    public static <L,R> Either<L,R> right(R value) {
+        return new Either<>(Optional.<L>absent(), Optional.of(value));
+    }
+
+    public static <L,R> Either<L,R> none() {
+        return new Either<>(Optional.<L>absent(), Optional.<R>absent());
+    }
+
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HdfsApiSupplier.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HdfsApiSupplier.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HdfsApiSupplier.java
new file mode 100644
index 0000000..25df8ce
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HdfsApiSupplier.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.internal;
+
+import com.google.common.base.Optional;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.utils.hdfs.HdfsApi;
+import org.apache.ambari.view.utils.hdfs.HdfsApiException;
+import org.apache.ambari.view.utils.hdfs.HdfsUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class HdfsApiSupplier implements ContextSupplier<Optional<HdfsApi>> {
+
+  protected final Logger LOG =
+    LoggerFactory.getLogger(getClass());
+
+  private static final Map<String, HdfsApi> hdfsApiMap = new ConcurrentHashMap<>();
+  private final Object lock = new Object();
+
+  @Override
+  public Optional<HdfsApi> get(ViewContext context) {
+    try {
+      if(!hdfsApiMap.containsKey(context.getInstanceName())) {
+        synchronized (lock) {
+          if(!hdfsApiMap.containsKey(context.getInstanceName())) {
+            LOG.debug("Creating HDFSApi instance for Viewname: {}, Instance Name: {}", context.getViewName(), context.getInstanceName());
+            HdfsApi api = HdfsUtil.connectToHDFSApi(context);
+            hdfsApiMap.put(context.getInstanceName(), api);
+            return Optional.of(api);
+          }
+        }
+      }
+      return Optional.of(hdfsApiMap.get(context.getInstanceName()));
+    } catch (HdfsApiException e) {
+      LOG.error("Cannot get the HDFS API", e);
+      return Optional.absent();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveConnectionWrapper.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveConnectionWrapper.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveConnectionWrapper.java
new file mode 100644
index 0000000..811df23
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveConnectionWrapper.java
@@ -0,0 +1,109 @@
+/*
+ * 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.ambari.view.hive2.internal;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import org.apache.hive.jdbc.HiveConnection;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * Composition over a Hive jdbc connection
+ * This class only provides a connection over which
+ * callers should run their own JDBC statements
+ */
+public class HiveConnectionWrapper implements Connectable,Supplier<HiveConnection> {
+
+  private static String DRIVER_NAME = "org.apache.hive.jdbc.HiveDriver";
+  private final String jdbcUrl;
+  private final String username;
+  private final String password;
+
+  private HiveConnection connection = null;
+
+  public HiveConnectionWrapper(String jdbcUrl, String username, String password) {
+    this.jdbcUrl = jdbcUrl;
+    this.username = username;
+    this.password = password;
+  }
+
+
+  @Override
+  public void connect() throws ConnectionException {
+    try {
+      Class.forName(DRIVER_NAME);
+    } catch (ClassNotFoundException e) {
+      throw new ConnectionException(e, "Cannot load the hive JDBC driver");
+    }
+
+    try {
+      Connection conn = DriverManager.getConnection(jdbcUrl, username, password);
+      connection = (HiveConnection)conn;
+
+    } catch (SQLException e) {
+      throw new ConnectionException(e, "Cannot open a hive connection with connect string " + jdbcUrl);
+    }
+
+
+  }
+
+  @Override
+  public void reconnect() throws ConnectionException {
+
+  }
+
+  @Override
+  public void disconnect() throws ConnectionException {
+    if (connection != null) {
+      try {
+        connection.close();
+      } catch (SQLException e) {
+        throw new ConnectionException(e, "Cannot close the hive connection with connect string " + jdbcUrl);
+      }
+    }
+  }
+
+  public Optional<HiveConnection> getConnection() {
+    return Optional.fromNullable(connection);
+  }
+
+  @Override
+  public boolean isOpen() {
+    try {
+      return connection != null && !connection.isClosed() && connection.isValid(100);
+    } catch (SQLException e) {
+      // in case of an SQ error just return
+      return false;
+    }
+  }
+
+  /**
+   * Retrieves an instance of the appropriate type. The returned object may or
+   * may not be a new instance, depending on the implementation.
+   *
+   * @return an instance of the appropriate type
+   */
+  @Override
+  public HiveConnection get() {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveQuery.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveQuery.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveQuery.java
new file mode 100644
index 0000000..29f0db3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveQuery.java
@@ -0,0 +1,71 @@
+/*
+ * 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.ambari.view.hive2.internal;
+
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+
+import javax.annotation.Nullable;
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Holder for query submitted by the user
+ * This may contain multiple hive queries
+ */
+public class HiveQuery {
+
+    private String query;
+
+    public HiveQuery(String query) {
+        this.query = query;
+    }
+
+    public HiveQueries fromMultiLineQuery(String multiLineQuery){
+        return new HiveQueries(multiLineQuery);
+    }
+
+
+    public static class HiveQueries{
+
+        static final String QUERY_SEP = ";";
+        Collection<HiveQuery> hiveQueries;
+
+        private HiveQueries(String userQuery) {
+            hiveQueries = FluentIterable.from(Arrays.asList(userQuery.split(QUERY_SEP)))
+                    .transform(new Function<String, HiveQuery>() {
+                        @Nullable
+                        @Override
+                        public HiveQuery apply(@Nullable String input) {
+                            return new HiveQuery(input.trim());
+                        }
+                    }).toList();
+        }
+
+
+
+
+
+    }
+
+
+
+
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveResult.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveResult.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveResult.java
new file mode 100644
index 0000000..25696d2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveResult.java
@@ -0,0 +1,160 @@
+/*
+ * 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.ambari.view.hive2.internal;
+
+import com.google.common.collect.Lists;
+
+import java.math.RoundingMode;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+public class HiveResult implements Iterator<HiveResult.Row> {
+
+    public static final String NULL = "NULL";
+    private static final int DEFAULT_BATCH_SIZE = 50;
+    private static ResultSetMetaData metaData;
+    private Row colNames;
+    private NumberFormat nf = new DecimalFormat();
+    private List<Row> rows = Lists.newArrayList();
+
+    public HiveResult(ResultSet rs) throws SQLException {
+        nf.setRoundingMode(RoundingMode.FLOOR);
+        nf.setMinimumFractionDigits(0);
+        nf.setMaximumFractionDigits(2);
+        metaData = rs.getMetaData();
+        int columnCount = metaData.getColumnCount();
+        colNames = new Row(columnCount);
+        int index = 0;
+        while (rs.next() && index <DEFAULT_BATCH_SIZE){
+            index ++;
+            rows.add(new Row(columnCount,rs));
+        }
+
+
+    }
+
+    public List<Row> getRows(){
+        return rows;
+    }
+
+    public List<Row> getData() {
+        return rows;
+    }
+
+    /**
+     * use the lists iterator
+     *
+     * @return {@code true} if the iteration has more elements
+     */
+    @Override
+    public boolean hasNext() {
+        return rows.iterator().hasNext();
+    }
+
+    /**
+     * Returns the next row in the iteration.
+     *
+     * @return the next element in the iteration
+     */
+    @Override
+    public Row next() {
+        return rows.iterator().next();
+    }
+
+    /**
+     * Removes from the underlying collection the last element returned
+     * by this iterator (optional operation).  This method can be called
+     * only once per call to {@link #next}.  The behavior of an iterator
+     * is unspecified if the underlying collection is modified while the
+     * iteration is in progress in any way other than by calling this
+     * method.
+     *
+     * @throws UnsupportedOperationException if the {@code remove}
+     *                                       operation is not supported by this iterator
+     * @throws IllegalStateException         if the {@code next} method has not
+     *                                       yet been called, or the {@code remove} method has already
+     *                                       been called after the last call to the {@code next}
+     *                                       method
+     */
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Row getColNames() {
+        return colNames;
+    }
+
+
+    @Override
+    public String toString() {
+        return "HiveResult{" +
+                "colNames=" + colNames +
+                ", rows=" + rows +
+                '}';
+    }
+
+    public class Row {
+        String[] values;
+
+        public Row(int size) throws SQLException {
+            values = new String[size];
+            for (int i = 0; i < size; i++) {
+                values[i] = metaData.getColumnLabel(i + 1);
+            }
+        }
+
+
+        public Row(int size, ResultSet rs) throws SQLException {
+            values = new String[size];
+            for (int i = 0; i < size; i++) {
+                if (nf != null) {
+                    Object object = rs.getObject(i + 1);
+                    if (object == null) {
+                        values[i] = null;
+                    } else if (object instanceof Number) {
+                        values[i] = nf.format(object);
+                    } else {
+                        values[i] = object.toString();
+                    }
+                } else {
+                    values[i] = rs.getString(i + 1);
+                }
+                values[i] = values[i] == null ? NULL : values[i];
+
+            }
+
+        }
+
+        @Override
+        public String toString() {
+            return "Row{" +
+                    "values=" + Arrays.toString(values) +
+                    '}';
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveTask.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveTask.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveTask.java
new file mode 100644
index 0000000..3a682ec
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveTask.java
@@ -0,0 +1,53 @@
+/*
+ * 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.ambari.view.hive2.internal;
+
+public interface HiveTask {
+
+    /**
+     * The task id for this task
+     * @return task Id
+     */
+    Long getId();
+
+    /**
+     * The user for which this task was submitted
+     * @return
+     */
+    String getUser();
+
+    /**
+     * The view instance tied to this task
+     * @return
+     */
+    String getInstance();
+
+    /**
+     * Connection properties pulled from the view context and request
+     * @return
+     */
+
+    //Connectable getConnectionClass();
+
+    ConnectionProperties getConnectionProperties();
+
+    HiveQuery.HiveQueries getQueries();
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveTaskMessage.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveTaskMessage.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveTaskMessage.java
new file mode 100644
index 0000000..7002f28
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveTaskMessage.java
@@ -0,0 +1,118 @@
+/*
+ * 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.ambari.view.hive2.internal;
+
+public class HiveTaskMessage implements HiveTask {
+
+    private Long id;
+    private String instance;
+    private ConnectionProperties connectionProps;
+    private HiveQuery.HiveQueries queries;
+    //private Connectable connectable = new HiveConnectionWrapper(connectMessage);
+
+
+    public void setConnectionProps(ConnectionProperties connectionProps) {
+        this.connectionProps = connectionProps;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public void setInstance(String instance) {
+        this.instance = instance;
+    }
+
+    public void setQueries(HiveQuery.HiveQueries queries) {
+        this.queries = queries;
+    }
+
+
+    /*public void setConnectable(Connectable connectable) {
+        this.connectable = connectable;
+    }*/
+
+    /**
+     * The task id for this task
+     *
+     * @return task Id
+     */
+    @Override
+    public Long getId() {
+        return id;
+    }
+
+    /**
+     * The user for which this task was submitted
+     *
+     * @return
+     */
+    @Override
+    public String getUser() {
+        return connectionProps.getUserName();
+    }
+
+    /**
+     * The view instance tied to this task
+     *
+     * @return
+     */
+    @Override
+    public String getInstance() {
+        return instance;
+    }
+
+    /**
+     * Connection properties pulled from the view context and request
+     *
+     * @return
+     */
+    /*@Override
+    public Connectable getConnectionClass() {
+        return connectable;
+    }
+*/
+    /**
+     * Connection properties pulled from the view context and request
+     *
+     * @return
+     */
+    @Override
+    public ConnectionProperties getConnectionProperties() {
+        return connectionProps;
+    }
+
+    @Override
+    public HiveQuery.HiveQueries getQueries() {
+        return queries;
+    }
+
+
+    @Override
+    public String toString() {
+        return "HiveTaskMessage{" +
+                "connectionProps=" + connectionProps +
+                ", id=" + id +
+                ", instance='" + instance + '\'' +
+                ", queries=" + queries +
+                '}';
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/DataStoreStorage.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/DataStoreStorage.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/DataStoreStorage.java
new file mode 100644
index 0000000..9adf129
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/DataStoreStorage.java
@@ -0,0 +1,172 @@
+/**
+ * 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.ambari.view.hive2.persistence;
+
+import org.apache.ambari.view.PersistenceException;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive2.persistence.utils.Indexed;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.apache.commons.beanutils.BeanUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.beans.Transient;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Engine for storing objects to context DataStore storage
+ */
+public class DataStoreStorage implements Storage {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(DataStoreStorage.class);
+
+  protected ViewContext context;
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public DataStoreStorage(ViewContext context) {
+    this.context = context;
+  }
+
+  @Override
+  public synchronized void store(Class model, Indexed obj) {
+    assignId(model, obj);
+
+    Indexed newBean;
+    try {
+      newBean = (Indexed) BeanUtils.cloneBean(obj);
+    } catch (IllegalAccessException e) {
+      throw new ServiceFormattedException("S010 Data storage error", e);
+    } catch (InstantiationException e) {
+      throw new ServiceFormattedException("S010 Data storage error", e);
+    } catch (InvocationTargetException e) {
+      throw new ServiceFormattedException("S010 Data storage error", e);
+    } catch (NoSuchMethodException e) {
+      throw new ServiceFormattedException("S010 Data storage error", e);
+    }
+    preprocessEntity(newBean);
+
+    try {
+      context.getDataStore().store(newBean);
+    } catch (PersistenceException e) {
+      throw new ServiceFormattedException("S020 Data storage error", e);
+    }
+  }
+
+  public void assignId(Class model, Indexed obj) {
+    if (obj.getId() == null) {
+      String id = nextIdForEntity(context, model);
+      obj.setId(id);
+    }
+  }
+
+  private void preprocessEntity(Indexed obj) {
+    cleanTransientFields(obj);
+  }
+
+  private void cleanTransientFields(Indexed obj) {
+    for (Method m : obj.getClass().getMethods()) {
+      Transient aTransient = m.getAnnotation(Transient.class);
+      if (aTransient != null && m.getName().startsWith("set")) {
+        try {
+          m.invoke(obj, new Object[]{ null });
+        } catch (IllegalAccessException e) {
+          throw new ServiceFormattedException("S030 Data storage error", e);
+        } catch (InvocationTargetException e) {
+          throw new ServiceFormattedException("S030 Data storage error", e);
+        }
+      }
+    }
+  }
+
+  private static synchronized String nextIdForEntity(ViewContext context, Class aClass) {
+    // auto increment id implementation
+    String lastId = context.getInstanceData(aClass.getName());
+    int newId;
+    if (lastId == null) {
+      newId = 1;
+    } else {
+      newId = Integer.parseInt(lastId) + 1;
+    }
+    context.putInstanceData(aClass.getName(), String.valueOf(newId));
+    return String.valueOf(newId);
+  }
+
+  @Override
+  public synchronized <T extends Indexed> T load(Class<T> model, Object id) throws ItemNotFound {
+    LOG.debug(String.format("Loading %s #%s", model.getName(), id));
+    try {
+      T obj = context.getDataStore().find(model, id);
+      if (obj != null) {
+        return obj;
+      } else {
+        throw new ItemNotFound();
+      }
+    } catch (PersistenceException e) {
+      throw new ServiceFormattedException("S040 Data storage error", e);
+    }
+  }
+
+  @Override
+  public synchronized <T extends Indexed> List<T> loadAll(Class<? extends T> model, FilteringStrategy filter) {
+    LinkedList<T> list = new LinkedList<T>();
+    LOG.debug(String.format("Loading all %s-s", model.getName()));
+    try {
+      for(T item: context.getDataStore().findAll(model, filter.whereStatement())) {
+        list.add(item);
+      }
+    } catch (PersistenceException e) {
+      throw new ServiceFormattedException("S050 Data storage error", e);
+    }
+    return list;
+  }
+
+  @Override
+  public synchronized <T extends Indexed> List<T> loadAll(Class<T> model) {
+    return loadAll(model, new OnlyOwnersFilteringStrategy(this.context.getUsername()));
+  }
+
+  @Override
+  public synchronized void delete(Class model, Object id) throws ItemNotFound {
+    LOG.debug(String.format("Deleting %s:%s", model.getName(), id));
+    Object obj = load(model, id);
+    try {
+      context.getDataStore().remove(obj);
+    } catch (PersistenceException e) {
+      throw new ServiceFormattedException("S060 Data storage error", e);
+    }
+  }
+
+  @Override
+  public boolean exists(Class model, Object id) {
+    try {
+      return context.getDataStore().find(model, id) != null;
+    } catch (PersistenceException e) {
+      throw new ServiceFormattedException("S070 Data storage error", e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/IStorageFactory.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/IStorageFactory.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/IStorageFactory.java
new file mode 100644
index 0000000..6c39359
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/IStorageFactory.java
@@ -0,0 +1,23 @@
+/**
+ * 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.ambari.view.hive2.persistence;
+
+public interface IStorageFactory {
+  Storage getStorage();
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/InstanceKeyValueStorage.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/InstanceKeyValueStorage.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/InstanceKeyValueStorage.java
new file mode 100644
index 0000000..86f2bfc
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/InstanceKeyValueStorage.java
@@ -0,0 +1,132 @@
+/**
+ * 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.ambari.view.hive2.persistence;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.utils.ContextConfigurationAdapter;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+import org.apache.commons.configuration.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.WebApplicationException;
+
+
+/**
+ * Persistent storage engine for storing java beans to
+ * instance data
+ */
+@Deprecated
+public class InstanceKeyValueStorage extends KeyValueStorage {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(InstanceKeyValueStorage.class);
+
+  private ContextConfigurationAdapter config = null;
+  private int VALUE_LENGTH_LIMIT = 254;
+
+  /**
+   * Constructor.
+   * @param context View Context instance
+   */
+  public InstanceKeyValueStorage(ViewContext context) {
+    super(context);
+  }
+
+  /**
+   * Returns config instance, adapter to Persistence API
+   * @return config instance
+   */
+  @Override
+  protected synchronized Configuration getConfig() {
+    if (config == null) {
+      config = new ContextConfigurationAdapter(context);
+    }
+    return config;
+  }
+
+  /**
+   * Value is limited to 256 symbols, this code splits value into chunks and saves them as <key>#<chunk_id>
+   * @param modelPropName key
+   * @param json value
+   */
+  protected void write(String modelPropName, String json) {
+    int saved = 0;
+    int page = 1;
+    while (saved < json.length()) {
+      int end = Math.min(saved + VALUE_LENGTH_LIMIT, json.length());
+      String substring = json.substring(saved, end);
+      getConfig().setProperty(modelPropName + "#" + page, substring);
+      saved += VALUE_LENGTH_LIMIT;
+      page += 1;
+      LOG.debug("Chunk saved: " + modelPropName + "#" + page + "=" + substring);
+    }
+    getConfig().setProperty(modelPropName, page - 1);
+    LOG.debug("Write finished: " + modelPropName + " pages:" + (page - 1));
+  }
+
+  /**
+   * Read chunked value (keys format <key>#<chunk_id>)
+   * @param modelPropName key
+   * @return value
+   */
+  protected String read(String modelPropName) {
+    StringBuilder result = new StringBuilder();
+    int pages = getConfig().getInt(modelPropName);
+    LOG.debug("Read started: " + modelPropName + " pages:" + pages);
+
+    for(int page = 1; page <= pages; page++) {
+      String substring = getConfig().getString(modelPropName + "#" + page);
+      LOG.debug("Chunk read: " + modelPropName + "#" + page + "=" + substring);
+      if (substring != null) {
+        result.append(substring);
+      }
+    }
+
+    return result.toString();
+  }
+
+  /**
+   * Remove chunked value (keys format <key>#<chunk_id>)
+   * @param modelPropName key
+   */
+  protected void clear(String modelPropName) {
+    int pages = getConfig().getInt(modelPropName);
+    LOG.debug("Clean started: " + modelPropName + " pages:" + pages);
+
+    for(int page = 1; page <= pages; page++) {
+      getConfig().clearProperty(modelPropName + "#" + page);
+      LOG.debug("Chunk clean: " + modelPropName + "#" + page);
+    }
+    getConfig().clearProperty(modelPropName);
+  }
+
+  public static void storageSmokeTest(ViewContext context) {
+    try {
+      final String property = "test.smoke.property";
+      context.putInstanceData(property, "42");
+      boolean status = context.getInstanceData(property).equals("42");
+      context.removeInstanceData(property);
+      if (!status) throw new ServiceFormattedException("Ambari Views instance data DB doesn't work properly", null);
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/KeyValueStorage.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/KeyValueStorage.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/KeyValueStorage.java
new file mode 100644
index 0000000..7b9c61c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/KeyValueStorage.java
@@ -0,0 +1,163 @@
+/**
+ * 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.ambari.view.hive2.persistence;
+
+import com.google.gson.Gson;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive2.persistence.utils.Indexed;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.persistence.utils.OnlyOwnersFilteringStrategy;
+import org.apache.commons.configuration.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Engine for storing objects to key-value storage
+ */
+public abstract class KeyValueStorage implements Storage {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(KeyValueStorage.class);
+  protected final Gson gson = new Gson();
+  protected ViewContext context;
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public KeyValueStorage(ViewContext context) {
+    this.context = context;
+  }
+
+  /**
+   * Returns config instance, adapter to Persistence API
+   * @return config instance
+   */
+  protected abstract Configuration getConfig();
+
+  @Override
+  public <T extends Indexed> void store(Class<T> model, Indexed obj) {
+    String modelIndexingPropName = getIndexPropertyName(model);
+
+    if (obj.getId() == null) {
+      int lastIndex = getConfig().getInt(modelIndexingPropName, 0);
+      lastIndex ++;
+      getConfig().setProperty(modelIndexingPropName, lastIndex);
+      obj.setId(String.valueOf(lastIndex));
+    }
+
+    String modelPropName = getItemPropertyName(model, obj.getId());
+    String json = serialize(obj);
+    write(modelPropName, json);
+  }
+
+  @Override
+  public <T extends Indexed> T load(Class<T> model, Object id) throws ItemNotFound {
+    String modelPropName = getItemPropertyName(model, id);
+    LOG.debug(String.format("Loading %s", modelPropName));
+    if (getConfig().containsKey(modelPropName)) {
+      String json = read(modelPropName);
+      LOG.debug(String.format("json: %s", json));
+
+      return deserialize(model, json);
+    } else {
+      throw new ItemNotFound();
+    }
+  }
+
+  /**
+   * Write json to storage
+   * @param modelPropName key
+   * @param json value
+   */
+  protected void write(String modelPropName, String json) {
+    getConfig().setProperty(modelPropName, json);
+  }
+
+  /**
+   * Read json from storage
+   * @param modelPropName key
+   * @return value
+   */
+  protected String read(String modelPropName) {
+    return getConfig().getString(modelPropName);
+  }
+
+  /**
+   * Remove line from storage
+   * @param modelPropName key
+   */
+  protected void clear(String modelPropName) {
+    getConfig().clearProperty(modelPropName);
+  }
+
+  protected String serialize(Indexed obj) {
+    return gson.toJson(obj);
+  }
+
+  protected <T extends Indexed> T deserialize(Class<T> model, String json) {
+    return gson.fromJson(json, model);
+  }
+
+  @Override
+  public synchronized <T extends Indexed> List<T> loadAll(Class<? extends T> model, FilteringStrategy filter) {
+    ArrayList<T> list = new ArrayList<T>();
+    String modelIndexingPropName = getIndexPropertyName(model);
+    LOG.debug(String.format("Loading all %s-s", model.getName()));
+    int lastIndex = getConfig().getInt(modelIndexingPropName, 0);
+    for(int i=1; i<=lastIndex; i++) {
+      try {
+        T item = load(model, i);
+        if ((filter == null) || filter.isConform(item)) {
+          list.add(item);
+        }
+      } catch (ItemNotFound ignored) {
+      }
+    }
+    return list;
+  }
+
+  @Override
+  public synchronized <T extends Indexed> List<T> loadAll(Class<T> model) {
+    return loadAll(model, new OnlyOwnersFilteringStrategy(this.context.getUsername()));
+  }
+
+  @Override
+  public synchronized void delete(Class model, Object id) {
+    LOG.debug(String.format("Deleting %s:%s", model.getName(), id));
+    String modelPropName = getItemPropertyName(model, id);
+    clear(modelPropName);
+  }
+
+  @Override
+  public boolean exists(Class model, Object id) {
+    return getConfig().containsKey(getItemPropertyName(model, id));
+  }
+
+  private String getIndexPropertyName(Class model) {
+    return String.format("%s:index", model.getName());
+  }
+
+  private String getItemPropertyName(Class model, Object id) {
+    return String.format("%s.%s", model.getName(), id);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/LocalKeyValueStorage.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/LocalKeyValueStorage.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/LocalKeyValueStorage.java
new file mode 100644
index 0000000..7293363
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/LocalKeyValueStorage.java
@@ -0,0 +1,69 @@
+/**
+ * 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.ambari.view.hive2.persistence;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.utils.MisconfigurationFormattedException;
+import org.apache.commons.configuration.ConfigurationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Persistent storage engine for storing java beans to
+ * properties file
+ * Path to file should be in 'dataworker.storagePath' parameter
+ */
+@Deprecated
+public class LocalKeyValueStorage extends KeyValueStorage {
+  private final static Logger LOG =
+      LoggerFactory.getLogger(LocalKeyValueStorage.class);
+
+  private PersistentConfiguration config = null;
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public LocalKeyValueStorage(ViewContext context) {
+    super(context);
+  }
+
+  /**
+   * Returns config instance
+   * @return config instance
+   */
+  @Override
+  protected synchronized PersistentConfiguration getConfig() {
+    if (config == null) {
+      String fileName = context.getProperties().get("dataworker.storagePath");
+      if (fileName == null) {
+        String msg = "dataworker.storagePath is not configured!";
+        LOG.error(msg);
+        throw new MisconfigurationFormattedException("dataworker.storagePath");
+      }
+      try {
+        config = new PersistentConfiguration(fileName);
+      } catch (ConfigurationException e) {
+        e.printStackTrace();
+      }
+    }
+    return config;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/PersistentConfiguration.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/PersistentConfiguration.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/PersistentConfiguration.java
new file mode 100644
index 0000000..222225d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/PersistentConfiguration.java
@@ -0,0 +1,52 @@
+/**
+ * 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.ambari.view.hive2.persistence;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
+
+import java.io.File;
+
+/**
+ * Configuration enables all necessary options for PropertiesConfiguration:
+ * auto-save, auto-reloading, no delimiter parsing and other
+ */
+@Deprecated
+public class PersistentConfiguration extends PropertiesConfiguration {
+  /**
+   * Constructor
+   * @param fileName path to data file
+   * @throws ConfigurationException
+   */
+  public PersistentConfiguration(String fileName) throws ConfigurationException {
+    super();
+
+    File config = new File(fileName);
+    setFile(config);
+    this.setAutoSave(true);
+    this.setReloadingStrategy(new FileChangedReloadingStrategy());
+    this.setDelimiterParsingDisabled(true);
+    this.setListDelimiter((char) 0);
+
+    if (config.exists()) {
+      this.load();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/Storage.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/Storage.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/Storage.java
new file mode 100644
index 0000000..2c962ba
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/Storage.java
@@ -0,0 +1,77 @@
+/**
+ * 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.ambari.view.hive2.persistence;
+
+import org.apache.ambari.view.hive2.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive2.persistence.utils.Indexed;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+
+import java.util.List;
+
+/**
+ * Object storage interface
+ */
+public interface Storage {
+  /**
+   * Persist object to DB. It should be Indexed
+   * @param obj object to save
+   */
+  <T extends Indexed> void store(Class<T> model, Indexed obj);
+
+  /**
+   * Load object
+   * @param model bean class
+   * @param id identifier
+   * @return bean instance
+   * @throws ItemNotFound thrown if item with id was not found in DB
+   */
+  <T extends Indexed> T load(Class<T> model, Object id) throws ItemNotFound;
+
+  /**
+   * Load all objects of given bean class
+   * @param model bean class
+   * @param filter filtering strategy (return only those objects that conform condition)
+   * @param <T> bean class
+   * @return list of filtered objects
+   */
+  <T extends Indexed> List<T> loadAll(Class<? extends T> model, FilteringStrategy filter);
+
+  /**
+   * Load all objects of given bean class
+   * @param model bean class
+   * @param <T> bean class
+   * @return list of all objects
+   */
+  <T extends Indexed> List<T> loadAll(Class<T> model);
+
+  /**
+   * Delete object
+   * @param model bean class
+   * @param id identifier
+   */
+  void delete(Class model, Object id) throws ItemNotFound;
+
+  /**
+   * Check is object exists
+   * @param model bean class
+   * @param id identifier
+   * @return true if exists
+   */
+  boolean exists(Class model, Object id);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/ContextConfigurationAdapter.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/ContextConfigurationAdapter.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/ContextConfigurationAdapter.java
new file mode 100644
index 0000000..8c907b8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/ContextConfigurationAdapter.java
@@ -0,0 +1,260 @@
+/**
+ * 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.ambari.view.hive2.persistence.utils;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.commons.configuration.Configuration;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Persistence API to Apache Configuration adapter
+ */
+@Deprecated
+public class ContextConfigurationAdapter implements Configuration {
+  private ViewContext context;
+
+  /**
+   * Constructor of adapter
+   * @param context View Context
+   */
+  public ContextConfigurationAdapter(ViewContext context) {
+    this.context = context;
+  }
+
+  @Override
+  public Configuration subset(String prefix) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return context.getInstanceData().isEmpty();
+  }
+
+  @Override
+  public boolean containsKey(String s) {
+    Map<String, String> data = context.getInstanceData();
+    return data.containsKey(s);
+  }
+
+  @Override
+  public void addProperty(String s, Object o) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void setProperty(String s, Object o) {
+    context.putInstanceData(s, o.toString());
+  }
+
+  @Override
+  public void clearProperty(String key) {
+    context.removeInstanceData(key);
+  }
+
+  @Override
+  public void clear() {
+    for (String key : context.getInstanceData().keySet())
+      context.removeInstanceData(key);
+  }
+
+  @Override
+  public Object getProperty(String key) {
+    return context.getInstanceData(key);
+  }
+
+  @Override
+  public Iterator getKeys(String s) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public Iterator getKeys() {
+    return context.getInstanceData().keySet().iterator();
+  }
+
+  @Override
+  public Properties getProperties(String s) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public boolean getBoolean(String s) {
+    return getBoolean(s, null);
+  }
+
+  @Override
+  public boolean getBoolean(String s, boolean b) {
+    return getBoolean(s, (Boolean)b);
+  }
+
+  @Override
+  public Boolean getBoolean(String s, Boolean aBoolean) {
+    String data = context.getInstanceData(s);
+    return (data != null)?Boolean.parseBoolean(data):aBoolean;
+  }
+
+  @Override
+  public byte getByte(String s) {
+    return getByte(s, null);
+  }
+
+  @Override
+  public byte getByte(String s, byte b) {
+    return getByte(s, (Byte)b);
+  }
+
+  @Override
+  public Byte getByte(String s, Byte aByte) {
+    String data = context.getInstanceData(s);
+    return (data != null)?Byte.parseByte(data):aByte;
+  }
+
+  @Override
+  public double getDouble(String s) {
+    return getDouble(s, null);
+  }
+
+  @Override
+  public double getDouble(String s, double v) {
+    return getDouble(s, (Double)v);
+  }
+
+  @Override
+  public Double getDouble(String s, Double aDouble) {
+    String data = context.getInstanceData(s);
+    return (data != null)?Double.parseDouble(data):aDouble;
+  }
+
+  @Override
+  public float getFloat(String s) {
+    return getFloat(s, null);
+  }
+
+  @Override
+  public float getFloat(String s, float v) {
+    return getFloat(s, (Float)v);
+  }
+
+  @Override
+  public Float getFloat(String s, Float aFloat) {
+    String data = context.getInstanceData(s);
+    return (data != null)?Float.parseFloat(data):aFloat;
+  }
+
+  @Override
+  public int getInt(String s) {
+    return getInteger(s, null);
+  }
+
+  @Override
+  public int getInt(String s, int i) {
+    return getInteger(s, i);
+  }
+
+  @Override
+  public Integer getInteger(String s, Integer integer) {
+    String data = context.getInstanceData(s);
+    return (data != null)?Integer.parseInt(data):integer;
+  }
+
+  @Override
+  public long getLong(String s) {
+    return getLong(s, null);
+  }
+
+  @Override
+  public long getLong(String s, long l) {
+    return getLong(s, (Long)l);
+  }
+
+  @Override
+  public Long getLong(String s, Long aLong) {
+    String data = context.getInstanceData(s);
+    return (data != null)?Long.parseLong(data):aLong;
+  }
+
+  @Override
+  public short getShort(String s) {
+    return getShort(s, null);
+  }
+
+  @Override
+  public short getShort(String s, short i) {
+    return getShort(s, (Short)i);
+  }
+
+  @Override
+  public Short getShort(String s, Short aShort) {
+    String data = context.getInstanceData(s);
+    return (data != null)?Short.parseShort(data):aShort;
+  }
+
+  @Override
+  public BigDecimal getBigDecimal(String s) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public BigDecimal getBigDecimal(String s, BigDecimal bigDecimal) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public BigInteger getBigInteger(String s) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public BigInteger getBigInteger(String s, BigInteger bigInteger) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public String getString(String s) {
+    return context.getInstanceData(s);
+  }
+
+  @Override
+  public String getString(String s, String s2) {
+    String data = getString(s);
+    return (data != null)?data:s2;
+  }
+
+  @Override
+  public String[] getStringArray(String s) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public List getList(String s) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public List getList(String s, List list) {
+    throw new UnsupportedOperationException();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/FilteringStrategy.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/FilteringStrategy.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/FilteringStrategy.java
new file mode 100644
index 0000000..cec204a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/FilteringStrategy.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.persistence.utils;
+
+/**
+ * Filtering strategy for stored objects
+ */
+public interface FilteringStrategy {
+  /**
+   * Check whether item conforms chosen filter or not
+   * @param item item to check
+   * @return true if item conforms this filter
+   */
+  boolean isConform(Indexed item);
+  String whereStatement();
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/Indexed.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/Indexed.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/Indexed.java
new file mode 100644
index 0000000..c45e32c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/Indexed.java
@@ -0,0 +1,36 @@
+/**
+ * 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.ambari.view.hive2.persistence.utils;
+
+/**
+ * Interface to represent item with identifier
+ */
+public interface Indexed {
+  /**
+   * Get the ID
+   * @return ID
+   */
+  String getId();
+
+  /**
+   * Set ID
+   * @param id ID
+   */
+  void setId(String id);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/ItemNotFound.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/ItemNotFound.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/ItemNotFound.java
new file mode 100644
index 0000000..ad2adce
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/ItemNotFound.java
@@ -0,0 +1,25 @@
+/**
+ * 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.ambari.view.hive2.persistence.utils;
+
+/**
+ * Thrown when item was not found in DB
+ */
+public class ItemNotFound extends Exception {
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/OnlyOwnersFilteringStrategy.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/OnlyOwnersFilteringStrategy.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/OnlyOwnersFilteringStrategy.java
new file mode 100644
index 0000000..c260ef4
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/OnlyOwnersFilteringStrategy.java
@@ -0,0 +1,38 @@
+/**
+ * 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.ambari.view.hive2.persistence.utils;
+
+public class OnlyOwnersFilteringStrategy implements FilteringStrategy {
+  private final String username;
+
+  public OnlyOwnersFilteringStrategy(String username) {
+    this.username = username;
+  }
+
+  @Override
+  public boolean isConform(Indexed item) {
+    Owned object = (Owned) item;
+    return object.getOwner().compareTo(username) == 0;
+  }
+
+  @Override
+  public String whereStatement() {
+    return "owner = '" + username + "'";
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/Owned.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/Owned.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/Owned.java
new file mode 100644
index 0000000..afa873b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/Owned.java
@@ -0,0 +1,36 @@
+/**
+ * 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.ambari.view.hive2.persistence.utils;
+
+/**
+ * Interface to represent item with owner
+ */
+public interface Owned {
+  /**
+   * Get the owner
+   * @return owner
+   */
+  String getOwner();
+
+  /**
+   * Set owner
+   * @param owner owner
+   */
+  void setOwner(String owner);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/PersonalResource.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/PersonalResource.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/PersonalResource.java
new file mode 100644
index 0000000..02dc2b3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/PersonalResource.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
+ *
+ *     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.ambari.view.hive2.persistence.utils;
+
+public interface PersonalResource extends Indexed, Owned {
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/StorageFactory.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/StorageFactory.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/StorageFactory.java
new file mode 100644
index 0000000..2fa16fb
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/persistence/utils/StorageFactory.java
@@ -0,0 +1,69 @@
+/**
+ * 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.ambari.view.hive2.persistence.utils;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive2.persistence.DataStoreStorage;
+import org.apache.ambari.view.hive2.persistence.IStorageFactory;
+import org.apache.ambari.view.hive2.persistence.LocalKeyValueStorage;
+import org.apache.ambari.view.hive2.persistence.Storage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Storage factory, creates storage of Local or Persistence API type.
+ * Type depends on context configuration: if "dataworker.storagePath" is set,
+ * storage of Local type will be created.  Otherwise, Persistence API will be used.
+ *
+ * Storage is singleton.
+ */
+public class StorageFactory implements IStorageFactory {
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(StorageFactory.class);
+
+  private ViewContext context;
+
+  /**
+   * Constructor of storage factory
+   * @param context View Context instance
+   */
+  public StorageFactory(ViewContext context) {
+    this.context = context;
+  }
+
+  /**
+   * Creates storage instance
+   * @return storage instance
+   */
+  public Storage getStorage() {
+    String fileName = context.getProperties().get("dataworker.storagePath");
+
+    Storage storageInstance;
+    if (fileName != null) {
+      LOG.debug("Using local storage in " + fileName + " to store data");
+      // If specifed, use LocalKeyValueStorage - key-value file based storage
+      storageInstance = new LocalKeyValueStorage(context);
+    } else {
+      LOG.debug("Using Persistence API to store data");
+      // If not specifed, use ambari-views Persistence API
+      storageInstance = new DataStoreStorage(context);
+    }
+    return storageInstance;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/CRUDResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/CRUDResourceManager.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/CRUDResourceManager.java
new file mode 100644
index 0000000..dd475e7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/CRUDResourceManager.java
@@ -0,0 +1,131 @@
+/**
+ * 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.ambari.view.hive2.resources;
+
+import org.apache.ambari.view.hive2.persistence.IStorageFactory;
+import org.apache.ambari.view.hive2.persistence.Storage;
+import org.apache.ambari.view.hive2.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive2.persistence.utils.Indexed;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+import org.apache.ambari.view.hive2.utils.ServiceFormattedException;
+
+import java.util.List;
+
+/**
+ * CRUD resource manager
+ * @param <T> Data type with ID
+ */
+abstract public class CRUDResourceManager<T extends Indexed> implements IResourceManager<T> {
+  //TODO: refactor: generic parameter gets Fabric for Indexed objects, not objects itself
+  private Storage storage = null;
+
+  protected final Class<? extends T> resourceClass;
+  protected IStorageFactory storageFactory;
+
+  /**
+   * Constructor
+   * @param resourceClass model class
+   */
+  public CRUDResourceManager(Class<? extends T> resourceClass, IStorageFactory storageFactory) {
+    this.resourceClass = resourceClass;
+    this.storageFactory = storageFactory;
+  }
+  // CRUD operations
+
+  /**
+   * Create operation
+   * @param object object
+   * @return model object
+   */
+  @Override
+  public T create(T object) {
+    object.setId(null);
+    return this.save(object);
+  }
+
+  /**
+   * Read operation
+   * @param id identifier
+   * @return model object
+   * @throws org.apache.ambari.view.hive2.persistence.utils.ItemNotFound
+   */
+  @Override
+  public T read(Object id) throws ItemNotFound {
+    T object = null;
+    object = storageFactory.getStorage().load(this.resourceClass, id);
+    if (!checkPermissions(object))
+      throw new ItemNotFound();
+    return object;
+  }
+
+  /**
+   * Read all objects
+   * @param filteringStrategy filtering strategy
+   * @return list of filtered objects
+   */
+  @Override
+  public List<T> readAll(FilteringStrategy filteringStrategy) {
+    return storageFactory.getStorage().loadAll(this.resourceClass, filteringStrategy);
+  }
+
+  /**
+   * Update operation
+   * @param newObject new object
+   * @param id identifier of previous object
+   * @return model object
+   * @throws org.apache.ambari.view.hive2.persistence.utils.ItemNotFound
+   */
+  @Override
+  public T update(T newObject, String id) throws ItemNotFound {
+    newObject.setId(id);
+    this.save(newObject);
+    return newObject;
+  }
+
+  /**
+   * Delete operation
+   * @param resourceId object identifier
+   * @throws org.apache.ambari.view.hive2.persistence.utils.ItemNotFound
+   */
+  @Override
+  public void delete(Object resourceId) throws ItemNotFound {
+    if (!storageFactory.getStorage().exists(this.resourceClass, resourceId)) {
+      throw new ItemNotFound();
+    }
+    storageFactory.getStorage().delete(this.resourceClass, resourceId);
+  }
+
+  // UTILS
+
+  protected T save(T object) {
+    storageFactory.getStorage().store(resourceClass, object);
+    return object;
+  }
+
+  protected abstract boolean checkPermissions(T object);
+
+  protected void cleanupAfterErrorAndThrowAgain(Indexed object, ServiceFormattedException e) {
+    try {
+      delete(object.getId());
+    } catch (ItemNotFound itemNotFound) {
+      throw new ServiceFormattedException("E040 Item not found", itemNotFound);
+    }
+    throw e;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/IResourceManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/IResourceManager.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/IResourceManager.java
new file mode 100644
index 0000000..9eb6a1c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/IResourceManager.java
@@ -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.
+ */
+
+package org.apache.ambari.view.hive2.resources;
+
+import org.apache.ambari.view.hive2.persistence.utils.FilteringStrategy;
+import org.apache.ambari.view.hive2.persistence.utils.Indexed;
+import org.apache.ambari.view.hive2.persistence.utils.ItemNotFound;
+
+import java.util.List;
+
+public interface IResourceManager<T extends Indexed> {
+  T create(T object);
+
+  T read(Object id) throws ItemNotFound;
+
+  List<T> readAll(FilteringStrategy filteringStrategy);
+
+  T update(T newObject, String id) throws ItemNotFound;
+
+  void delete(Object resourceId) throws ItemNotFound;
+}


[07/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/queries.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/queries.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/queries.hbs
new file mode 100644
index 0000000..96e2498
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/queries.hbs
@@ -0,0 +1,96 @@
+{{!
+* 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.
+}}
+
+<table class="table">
+  <thead>
+    <tr>
+      {{#each column in columns}}
+        <th>
+          {{#if column.caption}}
+            {{column-filter-widget class="pull-left"
+                                   column=column
+                                   filterValue=column.filterValue
+                                   sortAscending=controller.sortAscending
+                                   sortProperties=controller.sortProperties
+                                   columnSorted="sort"
+                                   columnFiltered="filter"}}
+          {{else}}
+            {{column.caption}}
+          {{/if}}
+        </th>
+      {{/each}}
+      <th>
+        <button type="btn" class="btn btn-sm btn-warning pull-right clear-filters" {{action "clearFilters"}}>{{t "buttons.clearFilters"}}</button>
+      </th>
+    </tr>
+  </thead>
+  <tbody>
+    {{#if queries.length}}
+      {{#if model.length}}
+        {{#each query in this}}
+          {{#unless query.isNew}}
+            <tr>
+              <td>
+                {{#link-to "index.savedQuery" query}}
+                  {{query.shortQuery}}
+                {{/link-to}}
+              </td>
+
+              <td>
+                {{#link-to "index.savedQuery" query}}
+                  {{query.title}}
+                {{/link-to}}
+              </td>
+
+              <td>{{query.dataBase}}</td>
+
+              <td>{{query.owner}}</td>
+
+              <td>
+                {{#unless query.isNew}}
+                  <div class="btn-group pull-right">
+                    <span data-toggle="dropdown">
+                      <a class="fa fa-gear"></a>
+                    </span>
+                    <ul class="dropdown-menu" role="menu">
+                      {{#each link in controller.links}}
+                        <li {{action 'executeAction' link query}}><a>{{tb-helper link}}</a></li>
+                      {{/each}}
+                    </ul>
+                  </div>
+                {{/unless}}
+              </td>
+            </tr>
+          {{/unless}}
+        {{/each}}
+      {{else}}
+        <tr>
+          <td colspan="5">
+            <h4 class="empty-list">{{t "emptyList.savedQueries.noMatches"}}</h4>
+          </td>
+        </tr>
+      {{/if}}
+    {{else}}
+      <tr>
+        <td colspan="5">
+          <h4 class="empty-list">{{t "emptyList.savedQueries.noItems"}}</h4>
+        </td>
+      </tr>
+    {{/if}}
+  </tbody>
+</table>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/query-tabs.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/query-tabs.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/query-tabs.hbs
new file mode 100644
index 0000000..62b15c1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/query-tabs.hbs
@@ -0,0 +1,28 @@
+{{!
+* 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.
+}}
+
+{{#each tab in tabs}}
+    <span {{action tab.action tab}} {{bind-attr class=":query-menu-tab tabClassNames tab.iconClass tab.active:active tab.flash:flash" title="tab.tooltip" id="tab.id"}}>
+      {{#if tab.badge}}
+        <span class="badge">{{tab.badge}}</span>
+      {{/if}}
+      {{#if tab.text}}
+        {{tab.text}}
+      {{/if}}
+    </span>
+{{/each}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/redirect.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/redirect.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/redirect.hbs
new file mode 100644
index 0000000..b776fd2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/redirect.hbs
@@ -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.
+}}
+
+{{outlet}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/settings.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/settings.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/settings.hbs
new file mode 100644
index 0000000..e24c667
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/settings.hbs
@@ -0,0 +1,70 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*     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.
+}}
+
+<div class="editor-overlay settings-container fadeIn">
+  <div class='settings-controls'>
+    <button class="btn btn-success btn-xs" {{action 'add'}}><i class="fa fa-plus"></i> Add</button>
+
+    {{#if settings.length}}
+      <button class="btn btn-danger btn-xs" {{action 'removeAll'}}><i class="fa fa-minus"></i> Remove All</button>
+    {{/if}}
+
+    <button class="btn btn-success btn-xs pull-right" {{action 'saveDefaultSettings'}}><i class="fa fa-plus"></i> Save Default Settings</button>
+  </div>
+
+  {{#each setting in settings}}
+    <div class="setting col-md-12 col-sm-12">
+      <form>
+        <div class="form-group">
+          <div class="input-group">
+            <div class="input-group-addon">
+
+              <div {{bind-attr keyname="setting.key.name"}} class="typeahead-container">
+                {{typeahead-widget
+                    options=predefinedSettings
+                    excluded=excluded
+                    optionLabelPath="name"
+                    optionValuePath="name"
+                    plugins="remove_button,restore_on_backspace"
+                    selection=setting.key
+                    safeValue = setting.key.name
+                    create="addKey"
+                }}
+              </div>
+            </div>
+            <div {{bind-attr class=":input-group-addon setting.valid::has-error"}}>
+              <div class="setting-input-value">
+                {{#if setting.key.values}}
+                  {{select-widget items=setting.key.values
+                                  labelPath="value"
+                                  selectedValue=setting.selection
+                                  defaultLabelTranslation="placeholders.select.value"
+                  }}
+                {{else}}
+                  {{input class="input-sm form-control" placeholderTranslation="placeholders.select.value" value=setting.selection.value}}
+                {{/if}}
+              </div>
+
+              <span class="fa fa-times-circle remove pull-right" {{action 'remove' setting}}></span>
+            </div>
+          </div>
+        </div>
+      </form>
+    </div>
+  {{/each}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/splash.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/splash.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/splash.hbs
new file mode 100644
index 0000000..84c7a71
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/splash.hbs
@@ -0,0 +1,102 @@
+{{!
+* 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.
+}}
+
+<div class="spinner"></div>
+<div class="container-fluid">
+  <h1>Welcome to the Hive View</h1>
+  {{#if allTestsCompleted }}
+    <h3>Service checks completed.</h3>
+  {{else}}
+    <h3>Service checks in progress.</h3>
+  {{/if}}
+
+  {{#if errors}}
+    <div class="progress active">
+      <div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" {{bind-attr style="progressBarStyle"}}></div>
+    </div>
+  {{else}}
+    <div class="progress progress-striped active">
+      <div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" {{bind-attr style="progressBarStyle"}}></div>
+    </div>
+  {{/if}}
+
+  <table class="table">
+    <tbody>
+    <tr>
+      <td>
+        {{#if modelhdfsTestDone}}
+          {{#if modelhdfsTest}}
+            <i class="fa fa-check"></i>
+          {{else}}
+            <i class="fa fa-remove"></i>
+          {{/if}}
+        {{else}}
+          <i class="fa fa-arrow-right"></i>
+        {{/if}}
+      </td>
+      <td>hdfs service test</td>
+    </tr>
+    <tr>
+      <td>
+        {{#if modelhiveserverTestDone}}
+          {{#if modelhiveserverTest}}
+            <i class="fa fa-check"></i>
+          {{else}}
+            <i class="fa fa-remove"></i>
+          {{/if}}
+        {{else}}
+          <i class="fa fa-arrow-right"></i>
+        {{/if}}
+      </td>
+      <td>hiveserver service test</td>
+    </tr>
+    <tr>
+      <td>
+        {{#if modelatsTestDone}}
+          {{#if modelatsTest}}
+            <i class="fa fa-check"></i>
+          {{else}}
+            <i class="fa fa-remove"></i>
+          {{/if}}
+        {{else}}
+          <i class="fa fa-arrow-right"></i>
+        {{/if}}
+      </td>
+      <td>ats service test</td>
+    </tr>
+    </tbody>
+  </table>
+  {{#if errors}}
+    <h3>Issues detected</h3>
+    <p>{{{errors}}}</p>
+  {{/if}}
+  {{#if stackTrace}}
+    <a href="#" {{action "toggleStackTrace" post}}>
+      {{#if isExpanded}}
+        <i class="fa fa-minus"></i> Collapse Stack Trace
+      {{else}}
+        <<i class="fa fa-plus"></i> Expand Stack Trace
+      {{/if}}
+    </a>
+    {{#if isExpanded}}
+      <pre class="prettyprint">
+        {{stackTrace}}
+      </pre>
+    {{/if}}
+  {{/if}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/tez-ui.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/tez-ui.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/tez-ui.hbs
new file mode 100644
index 0000000..6f6df4c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/tez-ui.hbs
@@ -0,0 +1,31 @@
+{{!
+* 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.
+}}
+
+<div id="tez-ui" class="index-overlay">
+  {{#panel-widget headingTranslation="titles.query.tez"}}
+    {{#if dagURL}}
+      <iframe {{bind-attr src=dagURL}}></iframe>
+    {{else}}
+      {{#if error}}
+        <div class="alert alert-danger" role="alert"><strong>{{tb-helper error}}</strong></div>
+      {{else}}
+        <div class="alert alert-danger" role="alert"><strong>{{tb-helper 'tez.errors.no.dag'}}</strong></div>
+      {{/if}}
+    {{/if}}
+  {{/panel-widget}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/udfs.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/udfs.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/udfs.hbs
new file mode 100644
index 0000000..7650fba
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/udfs.hbs
@@ -0,0 +1,53 @@
+{{!
+* 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.
+}}
+
+<table class="table">
+  <thead>
+    <tr>
+      <th>{{t "columns.fileResource"}}</th>
+      {{#each column in columns}}
+        <th>
+          {{column-filter-widget class="pull-left"
+                                 column=column
+                                 filterValue=column.filterValue
+                                 sortAscending=controller.sortAscending
+                                 sortProperties=controller.sortProperties
+                                 columnSorted="sort"
+                                 columnFiltered="filter"}}
+        </th>
+      {{/each}}
+      <th>
+        <div class="pull-right">
+          <button type="button" class="btn btn-sm btn-warning clear-filters" {{action "clearFilters"}}>{{t "buttons.clearFilters"}}</button>
+          <button type="button" class="btn btn-sm btn-success add-udf" {{action "add"}}>{{t "buttons.newUdf"}}</button>
+        </div>
+      </th>
+    </tr>
+  </thead>
+  <tbody>
+    {{#each udf in this}}
+      {{udf-tr-view udf=udf
+                    fileResources=fileResources
+                    columns=columns
+                    onAddFileResource="handleAddFileResource"
+                    onDeleteFileResource="handleDeleteFileResource"
+                    onSaveUdf="handleSaveUdf"
+                    onDeleteUdf='handleDeleteUdf'}}
+    {{/each}}
+  </tbody>
+</table>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/upload-table.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/upload-table.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/upload-table.hbs
new file mode 100644
index 0000000..b7d9011
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/upload-table.hbs
@@ -0,0 +1,168 @@
+{{!
+* 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.
+}}
+
+<div style="width : 90%">
+  <div class="main-content">
+    {{#if showErrors}}
+      {{render 'messages'}}
+    {{/if}}
+  </div>
+</div>
+
+<div id="uploadProgressModal" class="modal fade" role="dialog" data-backdrop="static">
+  <div class="modal-dialog">
+
+    <!-- Modal content-->
+    <div class="modal-content">
+      <div class="modal-header">
+        <h4 class="modal-title">Upload Progress</h4>
+      </div>
+      <div class="modal-body">
+        <p>
+        <ul>
+          {{uploadProgressInfo}}
+        </ul>
+        </p>
+      </div>
+    </div>
+
+  </div>
+</div>
+
+<div class="pull-right">
+  <i class="query-menu-tab fa queries-icon fa-envelope" {{ action 'toggleErrors'}}></i>
+</div>
+<div {{bind-attr class="showErrors:hide-data:show-data"}}>
+  <div>
+    <table class="table data-upload-form pull-left">
+      <tr>
+        <td class="data-upload-form-label"><label>Upload from Local</label></td>
+        <td  class="data-upload-form-field"> {{radio-button value='local' checked=uploadSource}}</td>
+
+        <td class="data-upload-form-label"><label>Upload from HDFS</label></td>
+        <td  class="data-upload-form-field">{{radio-button value='hdfs' checked=uploadSource}}</td>
+      </tr>
+      <tr>
+        <td class="data-upload-form-label"><label>File type</label></td>
+        <td class="data-upload-form-field">
+          {{typeahead-widget
+          content=inputFileTypes
+          optionValuePath="id"
+          optionLabelPath="name"
+          selection=inputFileType
+          placeholder="Select File Type"}}
+        </td>
+
+
+        {{#if isLocalUpload }}
+          <td class="data-upload-form-label"><label>Select from local</label></td>
+          <td class="data-upload-form-field">{{file-upload  filesUploaded="filesUploaded"}}</td>
+        {{else}}
+          <td class="data-upload-form-label"><label>HDFS Path</label></td>
+          <td class="data-upload-form-field" id="hdfs-param">{{input type="text" class="form-control" placeholder="Enter full HDFS path" value=hdfsPath }}
+            <button style="margin-left: 5px; padding-top: 6px;padding-bottom: 6px; padding-right: 10px; padding-left: 10px;" type="button" {{action "previewFromHdfs"}}
+            {{bind-attr class=":btn :btn-sm :btn-default"}}>{{t "buttons.showPreview"}}</button></td>
+        {{/if}}
+      </tr>
+      {{#if rows}}
+        <tr>
+          <td class="data-upload-form-label"><label>Database</label></td>
+          <td class="data-upload-form-field">
+            {{typeahead-widget
+            content=controllers.databases.databases
+            optionValuePath="id"
+            optionLabelPath="name"
+            selection=selectedDatabase
+            placeholder="Select a Database"
+            }}
+          </td>
+
+          <td class="data-upload-form-label"><label>Table name</label></td>
+          <td
+            class="data-upload-form-field">{{input type="text" class="form-control" placeholder="Table Name" value=tableName }}</td>
+        </tr>
+        <tr>
+          <td class="data-upload-form-label"><label>Stored as</label></td>
+          <td class="data-upload-form-field">
+            {{typeahead-widget
+            content=fileTypes
+            selection=selectedFileType}}
+          </td>
+          {{#if inputFileTypeCSV }}
+            <td class="data-upload-form-label"><label>Is first row header ?</label></td>
+            <td class="data-upload-form-field">
+              {{input id="isFirstRowHeader" type="checkbox" checked=isFirstRowHeader }}
+            </td>
+
+          {{/if}}
+        </tr>
+      {{/if}}
+    </table>
+
+    <table class="pull-right">
+      <tr>
+        <td>
+          {{#if rows}}
+            <button type="button" {{action "uploadTable"}}
+              {{bind-attr class=":btn :btn-sm :btn-default"}}>{{t "buttons.uploadTable"}}</button>
+          {{/if}}
+        </td>
+      </tr>
+    </table>
+
+  </div>
+
+  <div>
+    {{#if rows}}
+      <div id="upload-table">
+        <table class="table table-expandable no-border">
+          <thead>
+          <tr>
+            {{#each column in header}}
+              <th>{{input placeholder="column-name" type="text" class="form-control" value=column.name}}</th>
+            {{/each}}
+          </tr>
+          <tr id="upload-controls">
+            {{#each column in header}}
+              <th>
+                <table>
+                  <tbody>
+                  <tr>
+                    <td>{{typeahead-widget content=dataTypes selection=column.type }}</td>
+                    {{input-header column=column dataTypes=dataTypes}}
+                  </tr>
+                  </tbody>
+                </table>
+              </th>
+            {{/each}}
+          </tr>
+          </thead>
+          <tbody>
+          {{#each row in rows}}
+            <tr>
+              {{#each item in row.row}}
+                <td>{{item}}</td>
+              {{/each}}
+            </tr>
+          {{/each}}
+          </tbody>
+        </table>
+      </div>
+    {{/if}}
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/visual-explain.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/visual-explain.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/visual-explain.hbs
new file mode 100644
index 0000000..bef0693
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/visual-explain.hbs
@@ -0,0 +1,93 @@
+{{!
+* 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.
+}}
+
+<div id="visual-explain" class="index-overlay">
+  {{#panel-widget headingTranslation="titles.query.visualExplain"}}
+
+  {{#if noquery}}
+    <div class="alert alert-danger" role="alert"><strong>{{tb-helper 'hive.errors.no.query'}}</strong></div>
+  {{/if}}
+
+  {{#unless showSpinner}}
+     <div class="spinner"></div>
+  {{/unless}}
+
+  <div id="no-visual-explain-graph"></div>
+
+  <div id="visual-explain-graph">
+    {{#each edge in view.edges}}
+      <div class="edge">
+        <div class="edge-path" {{bind-attr style="edge.style"}}>
+          {{edge.type}}
+        </div>
+       {{!--  <div class="edge-arrow" ></div> --}}
+      </div>
+    {{/each}}
+
+    <div class="nodes">
+      {{#each group in view.verticesGroups}}
+        <div class="node-container">
+          {{#if group.contents}}
+            {{#each node in group.contents}}
+              <div {{bind-attr class="node.isTableNode:table-node node.isOutputNode:output-node :node" title="node.id"}}>
+                {{#if node.isTableNode}}
+                  <p><strong>{{t 'labels.table'}}</strong></p>
+                  {{node.label}}
+                {{else}}
+                  {{#if node.isOutputNode}}
+                    {{node.label}}
+                  {{else}}
+                    <div class="node-heading">
+                      <strong>{{node.label}}</strong>
+                    </div>
+                    <div class="node-content">
+                      {{#each section in node.contents}}
+                        <p>
+                          {{#popover-widget classNames="fa fa-info-circle" titleTranslation="popover.visualExplain.statistics" }}
+                            {{section.statistics}}
+                          {{/popover-widget}}
+                          <strong>
+                            {{section.index}}. {{section.title}}
+                          </strong>
+                          {{section.value}}
+                        </p>
+
+                        {{#each field in section.fields}}
+                          {{#if field.value}}
+                            <p>{{field.label}} {{field.value}}</p>
+                          {{/if}}
+                        {{/each}}
+                      {{/each}}
+                    </div>
+                    {{progress-widget value=node.progress}}
+                  {{/if}}
+                {{/if}}
+              </div>
+            {{/each}}
+          {{else}}
+            <div class="node" {{bind-attr title="group.label"}}>
+              {{group.label}}
+            </div>
+          {{/if}}
+        </div>
+      {{/each}}
+    </div>
+  </div>
+
+  {{/panel-widget}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/visualization-ui.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/visualization-ui.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/visualization-ui.hbs
new file mode 100644
index 0000000..22cbaef
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/visualization-ui.hbs
@@ -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.
+}}
+
+<div id="visualization" class="index-overlay">
+  {{#panel-widget headingTranslation="titles.query.visualization"}}
+    {{#if error}}
+      <div class="alert alert-danger" role="alert"><strong>{{error}}</strong></div>
+    {{else}}
+      {{#if polestarUrl}}
+        <div class="max-rows" >
+          <label>Maximum Row Count: </label> {{input value=selectedRowCount placeholder=selectedRowCount }}
+          <button {{action "changeRowCount"}}>OK</button>
+        </div>
+        {{#visualization-tabs-widget tabs=visualizationTabs }}
+
+        {{/visualization-tabs-widget}}
+      {{else}}
+          <div class="alert alert-danger" role="alert"><strong>An unknown error occurred! Please try again later.</strong></div>
+      {{/if}}
+    {{/if}}
+  {{/panel-widget}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/transforms/date.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/transforms/date.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/transforms/date.js
new file mode 100644
index 0000000..716ab84
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/transforms/date.js
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import DS from 'ember-data';
+
+export default DS.Transform.extend({
+
+  deserialize: function (serialized) {
+    var type = typeof serialized;
+
+    if (type === "string") {
+      return new Date(Ember.Date.parse(serialized));
+    } else if (type === "number") {
+      return new Date(serialized);
+    } else if (serialized === null || serialized === undefined) {
+      // if the value is not present in the data,
+      // return undefined, not null.
+      return serialized;
+    } else {
+      return null;
+    }
+  },
+
+  serialize: function (date) {
+    if (date instanceof Date) {
+      // Serialize it as a number to maintain millisecond precision
+      return Number(date);
+    } else {
+      return null;
+    }
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/constants.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/constants.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/constants.js
new file mode 100644
index 0000000..e40e447
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/constants.js
@@ -0,0 +1,233 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import helpers from 'hive/utils/functions';
+
+export default Ember.Object.create({
+  appTitle: 'Hive',
+
+  /**
+   * This should reflect the naming conventions accross the application.
+   * Changing one value also means changing the filenames for the chain of files
+   * represented by that value (routes, controllers, models etc).
+   * This dependency goes both ways.
+  */
+  namingConventions: {
+    routes: {
+      index: 'index',
+      savedQuery: 'savedQuery',
+      historyQuery: 'historyQuery',
+      queries: 'queries',
+      history: 'history',
+      udfs: 'udfs',
+      logs: 'logs',
+      results: 'results',
+      explain: 'explain',
+      uploadTable :'upload-table',
+      visualization: 'visualization'
+    },
+
+    subroutes: {
+      savedQuery: 'index.savedQuery',
+      historyQuery: 'index.historyQuery',
+      jobLogs: 'index.historyQuery.logs',
+      jobResults: 'index.historyQuery.results',
+      jobExplain: 'index.historyQuery.explain'
+    },
+
+    index: 'index',
+    udf: 'udf',
+    udfs: 'udfs',
+    udfInsertPrefix: 'create temporary function ',
+    fileInsertPrefix: 'add jar ',
+    explainPrefix: 'EXPLAIN ',
+    explainFormattedPrefix: 'EXPLAIN FORMATTED ',
+    insertUdfs: 'insert-udfs',
+    job: 'job',
+    jobs: 'jobs',
+    history: 'history',
+    savedQuery: 'saved-query',
+    database: 'database',
+    databases: 'databases',
+    openQueries: 'open-queries',
+    visualExplain: 'visual-explain',
+    notify: 'notify',
+    tezUI: 'tez-ui',
+    file: 'file',
+    fileResource: 'file-resource',
+    alerts: 'alerts',
+    logs: 'logs',
+    results: 'results',
+    jobResults: 'index/history-query/results',
+    jobLogs: 'index/history-query/logs',
+    jobExplain: 'index/history-query/explain',
+    databaseTree: 'databases-tree',
+    databaseSearch: 'databases-search-results',
+    settings: 'settings',
+    jobProgress: 'job-progress',
+    queryTabs: 'query-tabs',
+    session: 'session'
+  },
+
+  hiveParameters: [
+    {
+      name: 'hive.tez.container.size',
+      validate: helpers.regexes.digits
+    },
+
+    {
+      name: 'hive.prewarm.enabled',
+      values: helpers.validationValues.bool
+    },
+    {
+      name: 'hive.prewarm.numcontainers',
+      validate: helpers.regexes.digits
+    },
+    {
+      name: 'hive.tez.auto.reducer.parallelism',
+      values: helpers.validationValues.bool
+    },
+    {
+      name: 'hive.execution.engine',
+      values: helpers.validationValues.execEngine
+    },
+    {
+      name: 'hive.vectorized.execution.enabled',
+      values: helpers.validationValues.bool
+    },
+    {
+      name: 'hive.auto.convert.join',
+      values: helpers.validationValues.bool
+    },
+    {
+      name: 'tez.am.resource.memory.mb',
+      validate: helpers.regexes.digits
+    },
+    {
+      name: 'tez.am.container.idle.release-timeout-min.millis',
+      validate: helpers.regexes.digits
+    },
+    {
+      name: 'tez.am.container.idle.release-timeout-max.millis',
+      validate: helpers.regexes.digits
+    },
+    {
+      name: 'tez.queue.name',
+      validate: helpers.regexes.name
+    },
+    {
+      name: 'tez.runtime.io.sort.mb',
+      validate: helpers.regexes.digits
+    },
+    {
+      name: 'tez.runtime.sort.threads',
+      validate: helpers.regexes.digits
+    },
+    {
+      name: 'tez.runtime.compress.codec',
+      validate: helpers.regexes.dotPath
+    },
+    {
+      name: 'tez.grouping.min-size',
+      validate: helpers.regexes.digits
+    },
+    {
+      name: 'tez.grouping.max-size',
+      validate: helpers.regexes.digits
+    },
+    {
+      name: 'tez.generate.debug.artifacts',
+      values: helpers.validationValues.bool
+    }
+  ],
+
+  jobReferrer: {
+    sample: 'sample',
+    explain: 'explain',
+    visualExplain: 'visualExplain',
+    job: 'job'
+  },
+
+  statuses: {
+    unknown: "UNKNOWN",
+    initialized: "INITIALIZED",
+    running: "RUNNING",
+    succeeded: "SUCCEEDED",
+    canceled: "CANCELED",
+    closed: "CLOSED",
+    error: "ERROR",
+    failed: 'FAILED',
+    killed: 'KILLED',
+    pending: "PENDING"
+  },
+
+  alerts: {
+    warning: 'warning',
+    error: 'danger',
+    success: 'success'
+  },
+
+  results: {
+    save: {
+      csv: 'Save as csv',
+      hdfs: 'Save to HDFS'
+    },
+    statuses: {
+      terminated: "TERMINATED",
+      runnable: "RUNNABLE"
+    }
+  },
+
+  //this can be replaced by a string.format implementation
+  adapter: {
+    version: '2.0.0',
+    instance: 'Hive',
+    apiPrefix: '/api/v1/views/HIVE/versions/',
+    instancePrefix: '/instances/',
+    resourcePrefix: 'resources/'
+  },
+
+  sampleDataQuery: 'SELECT * FROM %@ LIMIT 100;',
+
+  notify: {
+    ERROR:  {
+      typeClass : 'alert-danger',
+      typeIcon  : 'fa-exclamation-triangle'
+    },
+    WARN: {
+      typeClass : 'alert-warning',
+      typeIcon  : 'fa-times-circle'
+    },
+    SUCCESS: {
+      typeClass : 'alert-success',
+      typeIcon  : 'fa-check'
+    },
+    INFO: {
+      typeClass : 'alert-info',
+      typeIcon  : 'fa-info'
+    }
+  },
+
+  globalSettings: {
+    comment: "--Global Settings--\n\n"
+  },
+
+  defaultVisualizationRowCount: 10000
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/dag-rules.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/dag-rules.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/dag-rules.js
new file mode 100644
index 0000000..c854892
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/dag-rules.js
@@ -0,0 +1,141 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.ArrayProxy.create({
+  content: Ember.A(
+    [
+      {
+        targetOperator: 'TableScan',
+        targetProperty: 'alias:',
+        label: 'Table Scan:',
+
+        fields: [
+          {
+            label: 'filterExpr:',
+            targetProperty: 'filterExpr:'
+          }
+        ]
+      },
+      {
+        targetOperator: 'Filter Operator',
+        targetProperty: 'predicate:',
+        label: 'Filter:',
+
+        fields: []
+      },
+      {
+        targetOperator: 'Map Join Operator',
+        label: 'Map Join',
+
+        fields: []
+      },
+      {
+        targetOperator: 'Merge Join Operator',
+        label: 'Merge Join',
+
+        fields: []
+      },
+      {
+        targetOperator: 'Select Operator',
+        label: 'Select',
+
+        fields: []
+      },
+      {
+        targetOperator: 'Reduce Output Operator',
+        label: 'Reduce',
+
+        fields: [
+          {
+            label: 'Partition columns:',
+            targetProperty: 'Map-reduce partition columns:'
+          },
+          {
+            label: 'Key expressions:',
+            targetProperty: 'key expressions:'
+          },
+          {
+            label: 'Sort order:',
+            targetProperty: 'sort order:'
+          }
+        ]
+      },
+      {
+        targetOperator: 'File Output Operator',
+        label: 'File Output Operator',
+
+        fields: []
+      },
+      {
+        targetOperator: 'Group By Operator',
+        label: 'Group By:',
+
+        fields: [
+          {
+            label: 'Aggregations:',
+            targetProperties: 'aggregations:'
+          },
+          {
+            label: 'Keys:',
+            targetProperty: 'keys:'
+          }
+        ]
+      },
+      {
+        targetOperator: 'Limit',
+        targetProperty: 'Number of rows:',
+        label: 'Limit:',
+
+        fields: []
+      },
+      {
+        targetOperator: 'Extract',
+        label: 'Extract',
+
+        fields: []
+      },
+      {
+        targetOperator: 'PTF Operator',
+        label: 'Partition Table Function',
+
+        fields: []
+      },
+      {
+        targetOperator: 'Dynamic Partitioning Event Operator',
+        labelel: 'Dynamic Partitioning Event',
+
+        fields: [
+          {
+            label: 'Target column:',
+            targetProperty: 'Target column:'
+          },
+          {
+            label: 'Target Vertex:',
+            targetProperty: 'Target Vertex:'
+          },
+          {
+            label: 'Partition key expr:',
+            targetProperty: 'Partition key expr:'
+          }
+        ]
+      }
+    ]
+  )
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/functions.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/functions.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/functions.js
new file mode 100644
index 0000000..32d81d3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/functions.js
@@ -0,0 +1,139 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+/* globals moment */
+
+export default Ember.Object.create({
+  isInteger: function (x) {
+    return !isNaN(x);
+  },
+
+  isDate: function (date) {
+    return moment(date).isValid();
+  },
+
+  regexes: {
+    allUppercase: /^[^a-z]*$/,
+    whitespaces: /^(\s*).*$/,
+    digits: /^\d+$/,
+    name: /\w+/ig,
+    dotPath: /[a-z.]+/i,
+    setSetting: /^set\s+[\w-.]+(\s+|\s?)=(\s+|\s?)[\w-.]+(\s+|\s?);/gim
+  },
+
+  validationValues: {
+    bool: [
+      Ember.Object.create({
+        value: 'true'
+      }),
+      Ember.Object.create({
+        value: 'false'
+      })
+    ],
+
+    execEngine: [
+      Ember.Object.create({
+        value: 'tez'
+      }),
+      Ember.Object.create({
+        value: 'mr'
+      })
+    ]
+  },
+
+  insensitiveCompare: function (sourceString) {
+    var args = Array.prototype.slice.call(arguments, 1);
+
+    if (!sourceString) {
+      return false;
+    }
+
+    return !!args.find(function (arg) {
+      return sourceString.match(new RegExp('^' + arg + '$', 'i'));
+    });
+  },
+
+  insensitiveContains: function (sourceString, destString) {
+    return sourceString.toLowerCase().indexOf(destString.toLowerCase()) > -1;
+  },
+
+  convertToArray: function (inputObj) {
+    var array = [];
+
+    for (var key in inputObj) {
+      if (inputObj.hasOwnProperty(key)) {
+        array.pushObject({
+          name: key,
+          value: inputObj[key]
+        });
+      }
+    }
+    return array;
+  },
+
+  /**
+   * Convert number of seconds into time object HH MM SS
+   *
+   * @param integer secs Number of seconds to convert
+   * @return object
+   */
+  secondsToHHMMSS: function (secs) {
+    var hours = 0,
+      minutes = 0,
+      seconds = secs,
+      divisor_for_minutes,
+      divisor_for_seconds,
+      formattedVal = [];
+
+    if (seconds < 60) {
+      formattedVal.push(Ember.I18n.t('labels.secsShort', {
+        seconds: seconds
+      }));
+    } else {
+      hours = Math.floor(seconds / (60 * 60));
+
+      divisor_for_minutes = seconds % (60 * 60);
+      minutes = Math.floor(divisor_for_minutes / 60);
+
+      divisor_for_seconds = divisor_for_minutes % 60;
+      seconds = Math.ceil(divisor_for_seconds);
+
+      if (hours > 0) {
+        formattedVal.push(Ember.I18n.t('labels.hrsShort', {
+          hours: hours
+        }));
+      }
+      if (minutes > 0) {
+        formattedVal.push(Ember.I18n.t('labels.minsShort', {
+          minutes: minutes
+        }));
+      }
+      if (seconds > 0) {
+        formattedVal.push(Ember.I18n.t('labels.secsShort', {
+          seconds: seconds
+        }));
+      }
+
+    }
+
+    return formattedVal.join(' ');
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/index.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/index.js
new file mode 100644
index 0000000..204e67f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/index.js
@@ -0,0 +1,28 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.View.extend({
+  didInsertElement: function() {
+    this._super();
+    Ember.$('body').tooltip({
+      selector: '[data-toggle="tooltip"]'
+    });
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/message.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/message.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/message.js
new file mode 100644
index 0000000..45b0236
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/message.js
@@ -0,0 +1,36 @@
+  /**
+ * 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.
+ */
+import Ember from 'ember';
+import NotificationView from 'hive/views/notification';
+
+export default NotificationView.extend({
+  templateName : 'message',
+  removeLater  : Ember.K,
+  isExpanded  : false,
+  removeMessage: 'removeMessage',
+
+  actions: {
+    expand: function () {
+      this.toggleProperty('isExpanded');
+    },
+
+    close: function () {
+      this.get('controller').send('removeMessage', this.get('notification'));
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/messages.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/messages.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/messages.js
new file mode 100644
index 0000000..5e720c0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/messages.js
@@ -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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.View.extend({
+  didInsertElement: function () {
+    var target = this.$('#messages');
+    var panel = this.$('#messages .panel-body');
+
+    panel.css('min-height', $('.main-content').height());
+    target.animate({ width: $('.main-content').width() }, 'fast');
+  },
+
+  willDestroyElement: function () {
+    var target = this.$('#messages');
+    var panel = this.$('#messages .panel-body');
+
+    panel.css('min-height', 0);
+    target.css('width', 0);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/notification.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/notification.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/notification.js
new file mode 100644
index 0000000..1fd2ce8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/notification.js
@@ -0,0 +1,51 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.View.extend({
+  closeAfter         : 5000,
+  isHovering         : false,
+  templateName       : 'notification',
+  removeNotification : 'removeNotification',
+
+  setup: function () {
+    this.set('typeClass', this.get('notification.type.typeClass'));
+    this.set('typeIcon', this.get('notification.type.typeIcon'));
+  }.on('init'),
+
+  removeLater: function () {
+    Ember.run.later(this, function () {
+      if (this.get('isHovering')) {
+        this.removeLater();
+      } else if (this.element) {
+        this.send('close');
+      }
+    }, this.get('closeAfter'));
+  }.on('didInsertElement'),
+
+  mouseEnter: function () { this.set('isHovering', true);  },
+  mouseLeave: function () { this.set('isHovering', false); },
+
+  actions: {
+    close: function () {
+      this.remove();
+      this.get('parentView').send('removeNotification', this.get('notification'));
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/tez-ui.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/tez-ui.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/tez-ui.js
new file mode 100644
index 0000000..7601463
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/tez-ui.js
@@ -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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.View.extend({
+  didInsertElement: function () {
+    var target = this.$('#tez-ui');
+    var panel = this.$('#tez-ui .panel-body');
+
+    panel.css('min-height', $('.main-content').height());
+    target.animate({ width: $('.main-content').width() }, 'fast');
+  },
+
+  willDestroyElement: function () {
+    var target = this.$('#tez-ui');
+    var panel = this.$('#tez-ui .panel-body');
+
+    panel.css('min-height', 0);
+    target.css('width', 0);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/visual-explain.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/visual-explain.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/visual-explain.js
new file mode 100644
index 0000000..94cb05a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/visual-explain.js
@@ -0,0 +1,461 @@
+/**
+ * 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.
+ */
+
+/* globals dagre */
+
+import Ember from 'ember';
+import dagRules from '../utils/dag-rules';
+import utils from 'hive/utils/functions';
+
+export default Ember.View.extend({
+  verticesGroups: [],
+  edges: [],
+
+  willInsertElement: function () {
+    this.set('graph', new dagre.graphlib.Graph());
+  },
+
+  didInsertElement: function () {
+    this._super();
+
+    var target = this.$('#visual-explain');
+    var panel = this.$('#visual-explain .panel-body');
+
+    panel.css('min-height', $('.main-content').height());
+    target.animate({ width: $('.main-content').width() }, 'fast');
+
+    this.$('#visual-explain-graph').draggable();
+
+    if (this.get('controller.rerender')) {
+      this.renderDag();
+    }
+  },
+
+  willDestroyElement: function () {
+    var target = this.$('#visual-explain');
+    var panel = this.$('#visual-explain .panel-body');
+
+    panel.css('min-height', 0);
+    target.css('width', 0);
+  },
+
+  updateProgress: function () {
+    var verticesProgress = this.get('controller.verticesProgress');
+    var verticesGroups = this.get('verticesGroups');
+
+    if (!verticesGroups || !verticesProgress || !verticesProgress.length) {
+      return;
+    }
+
+    verticesGroups.forEach(function (verticesGroup) {
+      verticesGroup.contents.forEach(function (node) {
+        var progress = verticesProgress.findBy('name', node.get('label'));
+
+        if (progress) {
+          node.set('progress', progress.get('value'));
+        }
+      });
+    });
+  }.observes('controller.verticesProgress.@each.value', 'verticesGroups'),
+
+  jsonChanged: function () {
+    var json = this.get('controller.json');
+    this.renderDag();
+  }.observes('controller.json'),
+
+  getOffset: function (el) {
+    var _x = 0;
+    var _y = 0;
+    var _w = el.offsetWidth|0;
+    var _h = el.offsetHeight|0;
+    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
+        _x += el.offsetLeft - el.scrollLeft;
+        _y += el.offsetTop - el.scrollTop;
+        el = el.offsetParent;
+    }
+    return { top: _y, left: _x, width: _w, height: _h };
+  },
+
+  addEdge: function (div1, div2, thickness, type) {
+    var off1 = this.getOffset(div1);
+    var off2 = this.getOffset(div2);
+    // bottom right
+    var x1 = off1.left + off1.width / 2;
+    var y1 = off1.top + off1.height;
+    // top right
+    var x2 = off2.left + off2.width / 2;
+    var y2 = off2.top;
+    // distance
+    var length = Math.sqrt(((x2-x1) * (x2-x1)) + ((y2-y1) * (y2-y1)));
+    // center
+    var cx = ((x1 + x2) / 2) - (length / 2);
+    var cy = ((y1 + y2) / 2) - (thickness / 2) - 73;
+    // angle
+    var angle = Math.round(Math.atan2((y1-y2), (x1-x2)) * (180 / Math.PI));
+
+    if (angle < -90) {
+      angle = 180 + angle;
+    }
+
+    var style = "left: %@px; top: %@px; width: %@px; transform:rotate(%@4deg);";
+    style = style.fmt(cx, cy, length, angle);
+
+    var edgeType;
+
+    if (type) {
+      if (type === 'BROADCAST_EDGE') {
+        edgeType = 'BROADCAST';
+      } else {
+        edgeType = 'SHUFFLE';
+      }
+    }
+
+    this.get('edges').pushObject({
+      style: style,
+      type: edgeType
+    });
+  },
+
+  getNodeContents: function (operator, contents, table, vertex) {
+    var currentTable = table,
+      contents = contents || [],
+      nodeName,
+      node,
+      ruleNode,
+      nodeLabelValue,
+      self = this;
+
+    if (operator.constructor === Array) {
+      operator.forEach(function (childOperator) {
+        self.getNodeContents(childOperator, contents, currentTable, vertex);
+      });
+
+      return contents;
+    } else {
+      nodeName = Object.getOwnPropertyNames(operator)[0];
+      node = operator[nodeName];
+      ruleNode = dagRules.findBy('targetOperator', nodeName);
+
+      if (ruleNode) {
+        if (nodeName.indexOf('Map Join') > -1) {
+          nodeLabelValue = this.handleMapJoinNode(node, currentTable);
+          currentTable = null;
+        } else if (nodeName.indexOf('Merge Join') > -1) {
+          nodeLabelValue = this.handleMergeJoinNode(node, vertex);
+        } else {
+          nodeLabelValue = node[ruleNode.targetProperty];
+        }
+
+        contents.pushObject({
+          title: ruleNode.label,
+          statistics: node["Statistics:"],
+          index: contents.length + 1,
+          value: nodeLabelValue,
+          fields: ruleNode.fields.map(function (field) {
+            var value = node[field.targetProperty || field.targetProperties];
+
+            return {
+              label: field.label,
+              value: value
+            };
+          })
+        });
+
+        if (node.children) {
+          return this.getNodeContents(node.children, contents, currentTable, vertex);
+        } else {
+          return contents;
+        }
+      } else {
+        return contents;
+      }
+    }
+  },
+
+  handleMapJoinNode: function (node, table) {
+    var rows = table || "<rows from above>";
+    var firstTable = node["input vertices:"][0] || rows;
+    var secondTable = node["input vertices:"][1] || rows;
+
+    var joinString = node["condition map:"][0][""];
+    joinString = joinString.replace("0", firstTable);
+    joinString = joinString.replace("1", secondTable);
+    joinString += " on ";
+    joinString += node["keys:"][0] + "=";
+    joinString += node["keys:"][1];
+
+    return joinString;
+  },
+
+  handleMergeJoinNode: function (node, vertex) {
+    var graphData = this.get('controller.json')['STAGE PLANS']['Stage-1']['Tez'];
+    var edges = graphData['Edges:'];
+    var index = 0;
+    var joinString = node["condition map:"][0][""];
+
+    edges[vertex].toArray().forEach(function (edge) {
+      if (edge.type === "SIMPLE_EDGE") {
+        joinString.replace(String(index), edge.parent);
+        index++;
+      }
+    });
+
+    return joinString;
+  },
+
+  //sets operator nodes
+  setNodes: function (vertices) {
+    var g = this.get('graph');
+    var self = this;
+
+    vertices.forEach(function (vertex) {
+      var contents = [];
+      var operator;
+      var currentTable;
+
+      if (vertex.name.indexOf('Map') > -1) {
+        if (vertex.value && vertex.value['Map Operator Tree:']) {
+          operator = vertex.value['Map Operator Tree:'][0];
+          currentTable = operator["TableScan"]["alias:"];
+        } else {
+          //https://hortonworks.jira.com/browse/BUG-36168
+          operator = "None";
+        }
+      } else if (vertex.name.indexOf('Reducer') > -1) {
+        operator = vertex.value['Reduce Operator Tree:'];
+      }
+
+      if (operator) {
+        contents = self.getNodeContents(operator, null, currentTable, vertex.name);
+
+        g.setNode(vertex.name, {
+          contents: contents,
+          id: vertex.name,
+          label: vertex.name
+        });
+      }
+    });
+
+    return this;
+  },
+
+  //sets edges between operator nodes
+  setEdges: function (edges) {
+    var g = this.get('graph');
+    var invalidEdges = [];
+    var edgesToBeRemoved = [];
+    var isValidEdgeType = function (type) {
+      return type === "SIMPLE_EDGE" ||
+             type === "BROADCAST_EDGE";
+    };
+
+    edges.forEach(function (edge) {
+      var parent;
+      var type;
+
+      if (edge.value.constructor === Array) {
+        edge.value.forEach(function (childEdge) {
+          parent = childEdge.parent;
+          type = childEdge.type;
+
+          if (isValidEdgeType(type)) {
+            g.setEdge(parent, edge.name);
+            g.edge({v: parent, w: edge.name}).type = type;
+          } else {
+            invalidEdges.pushObject({
+              vertex: edge.name,
+              edge: childEdge
+            });
+          }
+        });
+      } else {
+        parent = edge.value.parent;
+        type = edge.value.type;
+
+        if (isValidEdgeType(type)) {
+          g.setEdge(parent, edge.name);
+          g.edge({v: parent, w: edge.name}).type = type;
+        } else {
+          invalidEdges.pushObject({
+            vertex: edge.name,
+            edge: edge.name
+          });
+        }
+      }
+    });
+
+    invalidEdges.forEach(function (invalidEdge) {
+      var parent;
+      var targetEdge = g.edges().find(function (graphEdge) {
+        return graphEdge.v === invalidEdge.edge.parent ||
+               graphEdge.w === invalidEdge.edge.parent;
+      });
+
+      var targetVertex;
+
+      if (targetEdge) {
+        edgesToBeRemoved.pushObject(targetEdge);
+
+        if (targetEdge.v === invalidEdge.edge.parent) {
+          targetVertex = targetEdge.w;
+        } else {
+          targetVertex = targetEdge.v;
+        }
+
+        parent = invalidEdge.vertex;
+
+        g.setEdge({v: parent, w: targetVertex});
+        g.setEdge({v: parent, w: targetVertex}).type = "BROADCAST_EDGE";
+      }
+    });
+
+    edgesToBeRemoved.uniq().forEach(function (edge) {
+      g.removeEdge(edge.v, edge.w, edge.name);
+    });
+
+    return this;
+  },
+
+  //sets nodes for tables and their edges
+  setTableNodesAndEdges: function (vertices) {
+    var g = this.get('graph');
+
+    vertices.forEach(function (vertex) {
+      var operator;
+      var table;
+      var id;
+
+      if (vertex.name.indexOf('Map') > -1 && vertex.value && vertex.value['Map Operator Tree:']) {
+        operator = vertex.value['Map Operator Tree:'][0];
+        for (var node in operator) {
+          table = operator[node]['alias:'];
+
+          //create unique identifier by using table + map pairs so that we have
+          //different nodes for the same table if it's a table connected to multiple Map operators
+          id = table + ' for ' + vertex.name;
+
+          g.setNode(id, { id: id, label: table, isTableNode: true });
+          g.setEdge(id, vertex.name);
+        }
+      }
+    });
+
+    dagre.layout(g);
+
+    return this;
+  },
+
+  createNodeGroups: function () {
+    var groupedNodes = [];
+    var g = this.get('graph');
+    var lastRowNode;
+    var fileOutputOperator;
+
+    g.nodes().forEach(function (value) {
+      var node = g.node(value);
+
+      if (node) {
+        var existentRow = groupedNodes.findBy('topOffset', node.y);
+
+        if (!existentRow) {
+           groupedNodes.pushObject({
+              topOffset: node.y,
+              contents: [ Ember.Object.create(node) ]
+           });
+        } else {
+          existentRow.contents.pushObject(Ember.Object.create(node));
+        }
+      }
+    });
+
+    groupedNodes = groupedNodes.sortBy('topOffset');
+    groupedNodes.forEach(function (group) {
+      group.contents = group.contents.sortBy('x');
+    });
+
+    lastRowNode = groupedNodes.get('lastObject.contents.lastObject');
+    fileOutputOperator = lastRowNode.contents.get('lastObject');
+
+    g.setNode(fileOutputOperator.title, { id: fileOutputOperator.title, label: fileOutputOperator.title, isOutputNode: true });
+    g.setEdge(fileOutputOperator.title, lastRowNode.id);
+
+    groupedNodes.pushObject({
+      contents: [ Ember.Object.create(g.node(fileOutputOperator.title)) ]
+    });
+
+    lastRowNode.contents.removeObject(fileOutputOperator);
+
+    this.set('verticesGroups', groupedNodes);
+
+    return this;
+  },
+
+  renderEdges: function () {
+    var self = this;
+    var g = this.get('graph');
+
+    Ember.run.later(function () {
+      g.edges().forEach(function (value) {
+        var firstNode = self.$("[title='" + value.v + "']");
+        var secondNode = self.$("[title='" + value.w + "']");
+
+        if (firstNode && secondNode) {
+          self.addEdge(firstNode[0], secondNode[0], 2, g.edge(value).type);
+        }
+
+      });
+    }, 400);
+  },
+
+  renderDag: function () {
+    var json = this.get('controller.json');
+    var isVisualExplain = json && (json['STAGE PLANS'] != undefined) &&  (json['STAGE PLANS']['Stage-1'] != undefined) && (json['STAGE PLANS']['Stage-1']['Tez'] != undefined);
+    if (isVisualExplain) {
+      this.set('edges', []);
+
+      // Create a new directed graph
+      var g = this.get('graph');
+
+      var graphData = json['STAGE PLANS']['Stage-1']['Tez'];
+      var vertices = utils.convertToArray(graphData['Vertices:']);
+      var edges = utils.convertToArray(graphData['Edges:']);
+
+      // Set an object for the graph label
+      g.setGraph({});
+
+      // Default to assigning a new object as a label for each new edge.
+      g.setDefaultEdgeLabel(function () { return {}; });
+
+      this.setNodes(vertices)
+          .setEdges(edges)
+          .setTableNodesAndEdges(vertices)
+          .createNodeGroups()
+          .renderEdges();
+
+      this.set('controller.showSpinner', true);
+
+    } else {
+
+      if(!this.get('controller.noquery')) {
+        $('#no-visual-explain-graph').html('Visual explain is not available.');
+      }
+
+    }
+
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/visualization-ui.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/visualization-ui.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/visualization-ui.js
new file mode 100644
index 0000000..b1c10df
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/views/visualization-ui.js
@@ -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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.View.extend({
+  didInsertElement: function () {
+    var target = this.$('#visualization');
+    var panel = this.$('#visualization .panel-body').first();
+
+    panel.css('min-height', $('.main-content').height());
+    target.animate({ width: $('.main-content').width() }, 'fast');
+  },
+
+  willDestroyElement: function () {
+    var target = this.$('#visualization');
+    var panel = this.$('#visualization .panel-body');
+
+    panel.css('min-height', 0);
+    target.css('width', 0);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/big_tables.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/big_tables.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/big_tables.js
new file mode 100644
index 0000000..9f3a317
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/big_tables.js
@@ -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.
+ */
+
+var result = '';
+var tableCount = 15000;
+var columnCount = 100;
+
+//tables and columns script
+for (var i = 0; i < tableCount; i++) {
+  result += 'CREATE TABLE TABLE_' + i + ' (';
+  (function () {
+    for (var j = 0; j < columnCount; j++) {
+      result += 'field_' + j + ' STRING';
+
+      if (j < columnCount - 1) {
+        result += ',';
+      } else {
+        result += ') '
+      }
+    }
+  }());
+
+  result += "ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' STORED AS TEXTFILE; \nLOAD  DATA LOCAL INPATH 'test.csv' OVERWRITE INTO TABLE " +
+            'TABLE_' + i + ';\n\n';
+}
+
+console.log(result);
+
+//csv script
+var fill = '';
+for (var i = 0; i < columnCount; i++) {
+  fill += 'field_' + i;
+
+  if (i < columnCount - 1) {
+    fill += ', ';
+  }
+}
+
+console.log(fill);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/bower.json
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/bower.json b/contrib/views/hive-next/src/main/resources/ui/hive-web/bower.json
new file mode 100644
index 0000000..d029eff
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/bower.json
@@ -0,0 +1,28 @@
+{
+  "name": "hive",
+  "dependencies": {
+    "jquery": "1.11.3",
+    "ember": "1.10.0",
+    "ember-data": "1.0.0-beta.16.1",
+    "ember-resolver": "~0.1.12",
+    "loader.js": "stefanpenner/loader.js#3.2.0",
+    "ember-cli-shims": "stefanpenner/ember-cli-shims#0.0.3",
+    "ember-cli-test-loader": "rwjblue/ember-cli-test-loader#0.1.3",
+    "ember-load-initializers": "stefanpenner/ember-load-initializers#0.0.2",
+    "ember-qunit": "0.4.0",
+    "ember-qunit-notifications": "0.0.7",
+    "qunit": "1.18.0",
+    "bootstrap": "~3.2.0",
+    "ember-i18n": "~3.0.0",
+    "blanket": "~1.1.5",
+    "jquery-ui": "~1.11.2",
+    "selectize": "~0.12.0",
+    "pretender": "0.1.0",
+    "ember-uploader": "0.3.9",
+    "polestar": "https://github.com/hortonworks/polestar.git#0.7.2",
+    "voyager": "https://github.com/hortonworks/voyager.git#0.7.2"
+  },
+  "resolutions": {
+    "ember": "1.10.0"
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/config/environment.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/config/environment.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/config/environment.js
new file mode 100644
index 0000000..992d91c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/config/environment.js
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     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.
+ */
+
+/* jshint node: true */
+
+module.exports = function(environment) {
+  var ENV = {
+    modulePrefix: 'hive',
+    environment: environment,
+    baseURL: '/',
+    locationType: 'hash',
+    EmberENV: {
+      FEATURES: {
+        // Here you can enable experimental features on an ember canary build
+        // e.g. 'with-controller': true
+      }
+    },
+
+    contentSecurityPolicy: {
+      'connect-src': "'self' ws://localhost:35729 ws://0.0.0.0:35729",
+      'style-src': "'self' 'unsafe-inline'"
+    },
+
+    APP: {
+      // Here you can pass flags/options to your application instance
+      // when it is created
+    }
+  };
+
+  if (environment === 'development') {
+    // ENV.APP.LOG_RESOLVER = true;
+    ENV.APP.LOG_ACTIVE_GENERATION = true;
+    // ENV.APP.LOG_TRANSITIONS = true;
+    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
+    ENV.APP.LOG_VIEW_LOOKUPS = true;
+  }
+
+  if (environment === 'test') {
+    // Testem prefers this...
+    ENV.baseURL = '/';
+    ENV.locationType = 'auto';
+
+    // keep test console output quieter
+    ENV.APP.LOG_ACTIVE_GENERATION = false;
+    ENV.APP.LOG_VIEW_LOOKUPS = false;
+
+    ENV.APP.rootElement = '#ember-testing';
+  }
+
+  if (environment === 'production') {
+
+  }
+
+  return ENV;
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/package.json
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/package.json b/contrib/views/hive-next/src/main/resources/ui/hive-web/package.json
new file mode 100644
index 0000000..595b1f2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/package.json
@@ -0,0 +1,47 @@
+{
+  "name": "hive",
+  "version": "0.0.0",
+  "private": true,
+  "directories": {
+    "doc": "doc",
+    "test": "tests"
+  },
+  "scripts": {
+    "start": "ember server",
+    "build": "ember build",
+    "test": "ember test",
+    "preinstall": "chmod +x node/npm/bin/node-gyp-bin/node-gyp",
+    "postinstall": "bash node/with_new_path.sh node node_modules/.bin/bower --allow-root install"
+  },
+  "repository": "https://github.com/stefanpenner/ember-cli",
+  "engines": {
+    "node": ">= 0.10.32"
+  },
+  "author": "",
+  "license": "MIT",
+  "devDependencies": {
+    "body-parser": "^1.2.0",
+    "bower": ">= 1.3.12",
+    "broccoli-asset-rev": "^2.0.0",
+    "broccoli-sass": "0.6.3",
+    "ember-cli": "0.2.2",
+    "ember-cli-autoprefixer": "0.4.1",
+    "ember-cli-blanket": "^0.5.0",
+    "ember-cli-content-security-policy": "0.3.0",
+    "ember-cli-font-awesome": "0.0.4",
+    "ember-cli-htmlbars": "0.7.4",
+    "ember-cli-ic-ajax": "0.1.1",
+    "ember-cli-inject-live-reload": "^1.3.0",
+    "ember-cli-jquery-ui": "0.0.12",
+    "ember-cli-moment": "0.0.1",
+    "ember-cli-pretender": "^0.3.1",
+    "ember-cli-qunit": "0.3.14",
+    "ember-cli-selectize": "0.0.19",
+    "ember-cli-uglify": "1.0.1",
+    "ember-cli-uploader": "^0.3.9",
+    "ember-data": "1.0.0-beta.16.1",
+    "ember-dynamic-component": "0.0.1",
+    "ember-export-application-global": "^1.0.0",
+    "express": "^4.8.5"
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/testem.json
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/testem.json b/contrib/views/hive-next/src/main/resources/ui/hive-web/testem.json
new file mode 100644
index 0000000..78029a1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/testem.json
@@ -0,0 +1,10 @@
+{
+  "framework": "qunit",
+  "test_page": "tests/index.html?hidepassed&nocontainer",
+  "launch_in_ci": [
+    "PhantomJS"
+  ],
+  "launch_in_dev": [
+    "Chrome"
+  ]
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/.jshintrc
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/.jshintrc b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/.jshintrc
new file mode 100644
index 0000000..6ebf71a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/.jshintrc
@@ -0,0 +1,74 @@
+{
+  "predef": [
+    "document",
+    "window",
+    "location",
+    "setTimeout",
+    "$",
+    "-Promise",
+    "QUnit",
+    "define",
+    "console",
+    "equal",
+    "notEqual",
+    "notStrictEqual",
+    "test",
+    "asyncTest",
+    "testBoth",
+    "testWithDefault",
+    "raises",
+    "throws",
+    "deepEqual",
+    "start",
+    "stop",
+    "ok",
+    "strictEqual",
+    "module",
+    "moduleFor",
+    "moduleForComponent",
+    "moduleForModel",
+    "process",
+    "expect",
+    "visit",
+    "exists",
+    "fillIn",
+    "click",
+    "keyEvent",
+    "triggerEvent",
+    "find",
+    "findWithAssert",
+    "wait",
+    "DS",
+    "isolatedContainer",
+    "startApp",
+    "andThen",
+    "currentURL",
+    "currentPath",
+    "currentRouteName"
+  ],
+  "node": false,
+  "browser": false,
+  "boss": true,
+  "curly": false,
+  "debug": false,
+  "devel": false,
+  "eqeqeq": true,
+  "evil": true,
+  "forin": false,
+  "immed": false,
+  "laxbreak": false,
+  "newcap": true,
+  "noarg": true,
+  "noempty": false,
+  "nonew": false,
+  "nomen": false,
+  "onevar": false,
+  "plusplus": false,
+  "regexp": false,
+  "undef": true,
+  "sub": true,
+  "strict": false,
+  "white": false,
+  "eqnull": true,
+  "esnext": true
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/blanket-options.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/blanket-options.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/blanket-options.js
new file mode 100644
index 0000000..63e022b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/blanket-options.js
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+
+/*globals blanket, module */
+
+var options = {
+  modulePrefix: "hive",
+  filter: "//.*hive/.*/",
+  antifilter: "//.*(tests|template).*/",
+  loaderExclusions: ['ember-cli-jquery-ui', 'hive/config/environment'],
+  enableCoverage: true,
+  cliOptions: {
+    reporters: ['json']
+  }
+};
+
+if (typeof exports === 'undefined') {
+  blanket.options(options);
+} else {
+  module.exports = options;
+}


[30/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/QuickLinkArtifactResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/QuickLinkArtifactResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/QuickLinkArtifactResourceProvider.java
index 034aeb7..3e4b6aa 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/QuickLinkArtifactResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/QuickLinkArtifactResourceProvider.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.controller.internal;
 
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
@@ -138,8 +139,9 @@ public class QuickLinkArtifactResourceProvider extends AbstractControllerResourc
       String stackService = (String) properties.get(STACK_SERVICE_NAME_PROPERTY_ID);
 
       StackInfo stackInfo;
+      AmbariMetaInfo ambariMetaInfo = getManagementController().getAmbariMetaInfo();
       try {
-        stackInfo = getManagementController().getAmbariMetaInfo().getStack(stackName, stackVersion);
+        stackInfo = ambariMetaInfo.getStack(stackName, stackVersion);
       } catch (AmbariException e) {
         throw new NoSuchParentResourceException(String.format(
           "Parent stack resource doesn't exist: stackName='%s', stackVersion='%s'", stackName, stackVersion));
@@ -150,13 +152,19 @@ public class QuickLinkArtifactResourceProvider extends AbstractControllerResourc
       if (stackService == null) {
         serviceInfoList.addAll(stackInfo.getServices());
       } else {
-        ServiceInfo service = stackInfo.getService(stackService);
-        if (service == null) {
+        try {
+          ServiceInfo service = ambariMetaInfo.getService(stackName, stackVersion, stackService);
+          if (service == null) {
+            throw new NoSuchParentResourceException(String.format(
+                "Parent stack/service resource doesn't exist: stackName='%s', stackVersion='%s', serviceName='%s'",
+                stackName, stackVersion, stackService));
+          }
+          serviceInfoList.add(service);
+        } catch (AmbariException e) {
           throw new NoSuchParentResourceException(String.format(
-            "Parent stack/service resource doesn't exist: stackName='%s', stackVersion='%s', serviceName='%s'",
-            stackName, stackVersion, stackService));
+              "Parent stack/service resource doesn't exist: stackName='%s', stackVersion='%s', serviceName='%s'",
+              stackName, stackVersion, stackService));
         }
-        serviceInfoList.add(service);
       }
 
       for (ServiceInfo serviceInfo : serviceInfoList) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProvider.java
index 413dbff..49892cb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RemoteClusterResourceProvider.java
@@ -63,6 +63,7 @@ public class RemoteClusterResourceProvider extends AbstractAuthorizedResourcePro
    * Remote Cluster property id constants.
    */
   public static final String CLUSTER_NAME_PROPERTY_ID = "ClusterInfo/name";
+  public static final String CLUSTER_ID_PROPERTY_ID = "ClusterInfo/cluster_id";
   public static final String CLUSTER_URL_PROPERTY_ID  = "ClusterInfo/url";
   public static final String USERNAME_PROPERTY_ID = "ClusterInfo/username";
   public static final String PASSWORD_PROPERTY_ID = "ClusterInfo/password";
@@ -87,6 +88,7 @@ public class RemoteClusterResourceProvider extends AbstractAuthorizedResourcePro
   private static Set<String> propertyIds = new HashSet<String>();
   static {
     propertyIds.add(CLUSTER_NAME_PROPERTY_ID);
+    propertyIds.add(CLUSTER_ID_PROPERTY_ID);
     propertyIds.add(CLUSTER_URL_PROPERTY_ID);
     propertyIds.add(USERNAME_PROPERTY_ID);
     propertyIds.add(PASSWORD_PROPERTY_ID);
@@ -167,6 +169,7 @@ public class RemoteClusterResourceProvider extends AbstractAuthorizedResourcePro
   protected Resource toResource(Set<String> requestedIds, RemoteAmbariClusterEntity cluster) {
     Resource   resource   = new ResourceImpl(Resource.Type.RemoteCluster);
     setResourceProperty(resource, CLUSTER_NAME_PROPERTY_ID, cluster.getName(), requestedIds);
+    setResourceProperty(resource, CLUSTER_ID_PROPERTY_ID, cluster.getId(), requestedIds);
     setResourceProperty(resource, CLUSTER_URL_PROPERTY_ID, cluster.getUrl(), requestedIds);
     setResourceProperty(resource, USERNAME_PROPERTY_ID, cluster.getUsername(), requestedIds);
     ArrayList<String> services = new ArrayList<String>();
@@ -237,8 +240,14 @@ public class RemoteClusterResourceProvider extends AbstractAuthorizedResourcePro
       public Void invoke() throws AmbariException {
         String name = (String)properties.get(CLUSTER_NAME_PROPERTY_ID);
 
-        if(StringUtils.isEmpty(name)){
-          throw new IllegalArgumentException("Cluster Name cannot ne null or Empty");
+        if (StringUtils.isEmpty(name)) {
+          throw new IllegalArgumentException("Cluster Name cannot be null or Empty");
+        }
+
+        String id = (String)properties.get(CLUSTER_ID_PROPERTY_ID);
+
+        if (StringUtils.isEmpty(id)) {
+          throw new IllegalArgumentException("Cluster Id cannot be null or Empty");
         }
 
         saveOrUpdateRemoteAmbariClusterEntity(properties,true);
@@ -261,16 +270,24 @@ public class RemoteClusterResourceProvider extends AbstractAuthorizedResourcePro
     String username = (String)properties.get(USERNAME_PROPERTY_ID);
     String password = (String)properties.get(PASSWORD_PROPERTY_ID);
 
-    if(StringUtils.isEmpty(url) && StringUtils.isEmpty(username)){
+    if (StringUtils.isEmpty(url) && StringUtils.isEmpty(username)) {
       throw new IllegalArgumentException("Url or username cannot be null");
     }
 
-    RemoteAmbariClusterEntity entity = remoteAmbariClusterDAO.findByName(name);
+    RemoteAmbariClusterEntity entity ;
+
+    if (update) {
+      Long id = Long.valueOf((String) properties.get(CLUSTER_ID_PROPERTY_ID));
+      entity = remoteAmbariClusterDAO.findById(id);
+      if (entity == null) {
+        throw new IllegalArgumentException(String.format("Cannot find cluster with Id : \"%s\"", id));
+      }
+    } else {
 
-    if(update && entity == null){
-      throw new IllegalArgumentException(String.format("Cannot find cluster with name : \"%s\"",name));
-    }else if(!update && entity != null){
-      throw new DuplicateResourceException(String.format("Cluster with name : \"%s\" already exists",name));
+      entity = remoteAmbariClusterDAO.findByName(name);
+      if (entity != null) {
+        throw new DuplicateResourceException(String.format("Cluster with name : \"%s\" already exists", name));
+      }
     }
 
     // Check Password not null for create
@@ -288,7 +305,7 @@ public class RemoteClusterResourceProvider extends AbstractAuthorizedResourcePro
     entity.setName(name);
     entity.setUrl(url);
     try {
-      if(password != null) {
+      if (password != null) {
         entity.setUsername(username);
         entity.setPassword(password);
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupResourceProvider.java
new file mode 100644
index 0000000..ff67c5b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupResourceProvider.java
@@ -0,0 +1,759 @@
+/**
+ * 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.ambari.server.controller.internal;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+import jline.internal.Log;
+import org.apache.ambari.server.*;
+import org.apache.ambari.server.api.services.*;
+import org.apache.ambari.server.controller.*;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCacheKey;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCacheProvider;
+import org.apache.ambari.server.controller.spi.*;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCache;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCacheValue;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCacheProvider;
+import org.apache.ambari.server.security.authorization.AuthorizationException;
+import org.apache.ambari.server.security.authorization.AuthorizationHelper;
+import org.apache.ambari.server.security.authorization.ResourceType;
+import org.apache.ambari.server.security.authorization.RoleAuthorization;
+import org.apache.ambari.server.serveraction.kerberos.KerberosAdminAuthenticationException;
+import org.apache.ambari.server.serveraction.kerberos.KerberosInvalidConfigurationException;
+import org.apache.ambari.server.serveraction.kerberos.KerberosMissingAdminCredentialsException;
+import org.apache.ambari.server.state.*;
+import org.apache.ambari.server.utils.MapUtils;
+import org.apache.ambari.server.utils.StageUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.NotImplementedException;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.Validate;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.*;
+import java.net.URLEncoder;
+import java.io.OutputStream;
+
+/**
+ * Resource provider for service resources.
+ */
+public class ServiceGroupResourceProvider extends AbstractControllerResourceProvider {
+
+
+  // ----- Property ID constants ---------------------------------------------
+
+  // Services
+  public static final String SERVICE_GROUP_CLUSTER_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceGroupInfo", "cluster_name");
+  public static final String SERVICE_GROUP_SERVICE_GROUP_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceGroupInfo", "service_group_name");
+  public static final String SERVICE_GROUP_SERVICE_GROUP_DISPLAY_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceGroupInfo", "service_group_display_name");
+  public static final String SERVICE_GROUP_SERVICE_GROUP_TYPE_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceGroupInfo", "service_group_type");
+  public static final String SERVICE_GROUP_ASSEMBLY_FILE_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceGroupInfo", "assembly_file");
+  public static final String SERVICE_GROUP_DESIRED_STATE_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceGroupInfo", "desired_state");
+  public static final String SERVICE_GROUP_CURRENT_STATE_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceGroupInfo", "current_state");
+  public static final String SERVICE_GROUP_APPLICATION_ID_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceGroupInfo", "application_id");
+  public static final String SERVICE_GROUP_LIFETIME_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceGroupInfo", "lifetime");
+  public static final String SERVICE_GROUP_QUICKLINKS_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceGroupInfo", "quicklinks");
+  public static final String SERVICE_GROUP_CONTAINERS_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceGroupInfo", "containers");
+  public static final String SERVICE_GROUP_NUMBER_CONTAINERS_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceGroupInfo", "number_of_containers");
+  public static final String SERVICE_GROUP_EXPECTED_CONTAINERS_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceGroupInfo", "expected_number_of_containers");
+
+
+  private static Set<String> pkPropertyIds =
+      new HashSet<String>(Arrays.asList(new String[]{
+          SERVICE_GROUP_CLUSTER_NAME_PROPERTY_ID,
+          SERVICE_GROUP_SERVICE_GROUP_NAME_PROPERTY_ID}));
+
+  private static Map<String, String> componentNameMappings = MapUtils.fillMap("/var/lib/ambari-server/resources/componentsMap.dat");
+
+  private static Gson gson = StageUtils.getGson();
+
+  /**
+   * kerberos helper
+   */
+  @Inject
+  private KerberosHelper kerberosHelper;
+
+  private ServiceGroupCacheProvider cacheProvider;
+  private ServiceGroupCache cache;
+
+  // ----- Constructors ----------------------------------------------------
+
+  /**
+   * Create a  new resource provider for the given management controller.
+   *
+   * @param propertyIds           the property ids
+   * @param keyPropertyIds        the key property ids
+   * @param managementController  the management controller
+   */
+  @AssistedInject
+  public ServiceGroupResourceProvider(@Assisted Set<String> propertyIds,
+                                      @Assisted Map<Resource.Type, String> keyPropertyIds,
+                                      @Assisted AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+
+    setRequiredCreateAuthorizations(EnumSet.of(RoleAuthorization.SERVICE_ADD_DELETE_SERVICES));
+    setRequiredUpdateAuthorizations(RoleAuthorization.AUTHORIZATIONS_UPDATE_SERVICE);
+    setRequiredGetAuthorizations(RoleAuthorization.AUTHORIZATIONS_VIEW_SERVICE);
+    setRequiredDeleteAuthorizations(EnumSet.of(RoleAuthorization.SERVICE_ADD_DELETE_SERVICES));
+
+    this.cacheProvider = managementController.getServiceGroupCacheProvider();
+    this.cache = cacheProvider.getServiceGroupCache();
+  }
+
+  // ----- ResourceProvider ------------------------------------------------
+
+  @Override
+  protected RequestStatus createResourcesAuthorized(Request request)
+      throws SystemException,
+             UnsupportedPropertyException,
+             ResourceAlreadyExistsException,
+             NoSuchParentResourceException {
+
+    final Set<ServiceGroupRequest> requests = new HashSet<>();
+    for (Map<String, Object> propertyMap : request.getProperties()) {
+      requests.add(getRequest(propertyMap));
+    }
+    createResources(new Command<Void>() {
+      @Override
+      public Void invoke() throws AmbariException, AuthorizationException {
+        createServiceGroups(requests);
+        return null;
+      }
+    });
+    notifyCreate(Resource.Type.ServiceGroup, request);
+
+    return getRequestStatus(null);
+  }
+
+  @Override
+  protected Set<Resource> getResourcesAuthorized(Request request, Predicate predicate) throws
+      SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ServiceGroupRequest> requests = new HashSet<>();
+
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+      requests.add(getRequest(propertyMap));
+    }
+
+    Set<ServiceGroupResponse> responses = getResources(new Command<Set<ServiceGroupResponse>>() {
+      @Override
+      public Set<ServiceGroupResponse> invoke() throws AmbariException {
+        return getServiceGroups(requests);
+      }
+    });
+
+    Set<String>   requestedIds = getRequestPropertyIds(request, predicate);
+    Set<Resource> resources    = new HashSet<Resource>();
+
+    for (ServiceGroupResponse response : responses) {
+      Resource resource = new ResourceImpl(Resource.Type.ServiceGroup);
+      setResourceProperty(resource, SERVICE_GROUP_CLUSTER_NAME_PROPERTY_ID,
+          response.getClusterName(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_SERVICE_GROUP_NAME_PROPERTY_ID,
+          response.getServiceGroupName(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_SERVICE_GROUP_DISPLAY_NAME_PROPERTY_ID,
+          response.getServiceGroupDisplayName(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_SERVICE_GROUP_TYPE_PROPERTY_ID,
+          response.getServiceGroupType(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_ASSEMBLY_FILE_PROPERTY_ID,
+          response.getAssemblyFile(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_DESIRED_STATE_PROPERTY_ID,
+          response.getDesiredState(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_CURRENT_STATE_PROPERTY_ID,
+          response.getDesiredState(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_APPLICATION_ID_PROPERTY_ID,
+          response.getApplicationId(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_LIFETIME_PROPERTY_ID,
+          response.getLifetime(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_QUICKLINKS_PROPERTY_ID,
+          response.getQuickLinks(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_CONTAINERS_PROPERTY_ID,
+          response.getContainers(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_NUMBER_CONTAINERS_PROPERTY_ID,
+          response.getNumContainers(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_EXPECTED_CONTAINERS_PROPERTY_ID,
+          response.getExpectedContainers(), requestedIds);
+      resources.add(resource);
+    }
+    return resources;
+  }
+
+  @Override
+  protected RequestStatus updateResourcesAuthorized(final Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    RequestStageContainer requestStages = doUpdateResources(null, request, predicate);
+
+    RequestStatusResponse response = null;
+    if (requestStages != null) {
+      try {
+        requestStages.persist();
+      } catch (AmbariException e) {
+        throw new SystemException(e.getMessage(), e);
+      }
+      response = requestStages.getRequestStatusResponse();
+    }
+    notifyUpdate(Resource.Type.ServiceGroup, request, predicate);
+
+    return getRequestStatus(response);
+  }
+
+  @Override
+  protected RequestStatus deleteResourcesAuthorized(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ServiceGroupRequest> requests = new HashSet<>();
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+      requests.add(getRequest(propertyMap));
+    }
+    RequestStatusResponse response = modifyResources(new Command<RequestStatusResponse>() {
+      @Override
+      public RequestStatusResponse invoke() throws AmbariException, AuthorizationException {
+        return deleteServiceGroups(requests);
+      }
+    });
+
+    notifyDelete(Resource.Type.ServiceGroup, predicate);
+    return getRequestStatus(response);
+  }
+
+  @Override
+  public Set<String> checkPropertyIds(Set<String> propertyIds) {
+    propertyIds = super.checkPropertyIds(propertyIds);
+
+    if (propertyIds.isEmpty()) {
+      return propertyIds;
+    }
+    Set<String> unsupportedProperties = new HashSet<String>();
+    return unsupportedProperties;
+  }
+
+
+  // ----- AbstractResourceProvider ----------------------------------------
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+  // ----- utility methods -------------------------------------------------
+
+  private RequestStageContainer doUpdateResources(final RequestStageContainer stages, final Request request, Predicate predicate)
+      throws UnsupportedPropertyException, SystemException, NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ServiceGroupRequest> requests = new HashSet<>();
+    RequestStageContainer requestStages = null;
+
+    Iterator<Map<String,Object>> iterator = request.getProperties().iterator();
+    if (iterator.hasNext()) {
+      for (Map<String, Object> propertyMap : getPropertyMaps(iterator.next(), predicate)) {
+        requests.add(getRequest(propertyMap));
+      }
+
+      requestStages = modifyResources(new Command<RequestStageContainer>() {
+        @Override
+        public RequestStageContainer invoke() throws AmbariException, AuthorizationException {
+          return updateServiceGroup(stages, requests, request.getRequestInfoProperties());
+        }
+      });
+    }
+    return requestStages;
+  }
+
+  // Update services based on the given requests.
+  protected synchronized RequestStageContainer updateServiceGroup(RequestStageContainer requestStages,
+      Set<ServiceGroupRequest> requests, Map<String, String> requestProperties) throws AmbariException, AuthorizationException {
+
+    AmbariManagementController controller = getManagementController();
+    if (requests.isEmpty()) {
+      LOG.warn("Received an empty requests set");
+      return null;
+    }
+
+    Map<String, Set<String>> serviceGroupNames = new HashMap<>();
+    Map<State, List<ServiceGroup>> changedServiceGroups = new EnumMap<>(State.class);
+    Set<State> seenNewStates = new HashSet<>();
+    Clusters  clusters = controller.getClusters();
+    Set<String> clusterNames = new HashSet<>();
+
+    for (ServiceGroupRequest request : requests) {
+      if (request.getClusterName() == null
+          || request.getClusterName().isEmpty()
+          || request.getServiceGroupName() == null
+          || request.getServiceGroupName().isEmpty()) {
+        throw new IllegalArgumentException("Invalid arguments, cluster name"
+            + " and service group name should be provided to update service groups");
+      }
+
+      LOG.info("Received a updateServiceGroup request"
+          + ", clusterName=" + request.getClusterName()
+          + ", serviceGroupName=" + request.getServiceGroupName()
+          + ", request=" + request.toString());
+
+      clusterNames.add(request.getClusterName());
+
+      if (clusterNames.size() > 1) {
+        throw new IllegalArgumentException("Updates to multiple clusters is not"
+            + " supported");
+      }
+
+      if (!serviceGroupNames.containsKey(request.getClusterName())) {
+        serviceGroupNames.put(request.getClusterName(), new HashSet<String>());
+      }
+      if (serviceGroupNames.get(request.getClusterName())
+          .contains(request.getServiceGroupName())) {
+        // TODO throw single exception
+        throw new IllegalArgumentException("Invalid request contains duplicate"
+            + " service group names");
+      }
+      serviceGroupNames.get(request.getClusterName()).add(request.getServiceGroupName());
+
+      Cluster cluster = clusters.getCluster(request.getClusterName());
+      ServiceGroup sg = cluster.getServiceGroup(request.getServiceGroupName());
+      State oldState = sg.getCurrentState();
+      State newState = null;
+      if (request.getDesiredState() != null) {
+        newState = State.valueOf(request.getDesiredState());
+        if (!newState.isValidDesiredState()) {
+          throw new IllegalArgumentException("Invalid arguments, invalid"
+              + " desired state, desiredState=" + newState);
+        }
+      }
+
+      boolean persist = false;
+      if(request.getServiceGroupDisplayName() != null && !request.getServiceGroupDisplayName().equals(sg.getServiceGroupDisplayName())) {
+        sg.setServiceGroupDisplayName(request.getServiceGroupDisplayName());
+        persist = true;
+      }
+
+      if(request.getAssemblyFile() != null && !request.getAssemblyFile().equals(sg.getAssemblyFile())) {
+        sg.setAssemblyFile(request.getAssemblyFile());
+        persist = true;
+      }
+
+      if(persist) {
+        sg.persist();
+        LOG.info("Updated properties for service group " + sg.getName());
+      }
+
+      if (newState == null) {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Nothing to do for new updateServiceGroup request"
+              + ", clusterName=" + request.getClusterName()
+              + ", serviceName=" + request.getServiceGroupName()
+              + ", newDesiredState=null");
+        }
+        continue;
+      }
+
+      seenNewStates.add(newState);
+      if (newState != oldState) {
+        // The if user is trying to start or stop the service, ensure authorization
+        if (((newState == State.INSTALLED) || (newState == State.STARTED)) &&
+            !AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, cluster.getResourceId(), RoleAuthorization.SERVICE_START_STOP)) {
+          throw new AuthorizationException("The authenticated user is not authorized to start or stop services");
+        }
+
+        if (!State.isValidDesiredStateTransition(oldState, newState)) {
+          throw new AmbariException("Invalid transition for"
+              + " service group"
+              + ", clusterName=" + cluster.getClusterName()
+              + ", clusterId=" + cluster.getClusterId()
+              + ", serviceGroupName=" + sg.getName()
+              + ", currentDesiredState=" + oldState
+              + ", newDesiredState=" + newState);
+        }
+        // TODO: Remove block for stopping service groups
+        if (newState  == State.INSTALLED && oldState == State.STARTED ) {
+          throw new AmbariException("Stopping service groups not supported for"
+              + " service group"
+              + ", clusterName=" + cluster.getClusterName()
+              + ", clusterId=" + cluster.getClusterId()
+              + ", serviceGroupName=" + sg.getName()
+              + ", currentDesiredState=" + oldState
+              + ", newDesiredState=" + newState);
+        }
+        if (!changedServiceGroups.containsKey(newState)) {
+          changedServiceGroups.put(newState, new ArrayList<ServiceGroup>());
+        }
+        changedServiceGroups.get(newState).add(sg);
+      }
+    }
+    if (seenNewStates.size() > 1) {
+      // TODO should we handle this scenario
+      throw new IllegalArgumentException("Cannot handle different desired state"
+          + " changes for a set of services at the same time");
+    }
+    Cluster cluster = clusters.getCluster(clusterNames.iterator().next());
+
+    return controller.addServiceGroupStages(requestStages, cluster, requestProperties,
+        null, changedServiceGroups);
+  }
+
+  /**
+   * Get a service group request object from a map of property values.
+   *
+   * @param properties  the predicate
+   *
+   * @return the service request object
+   */
+  private ServiceGroupRequest getRequest(Map<String, Object> properties) {
+    ServiceGroupRequest svcRequest = new ServiceGroupRequest(
+        (String) properties.get(SERVICE_GROUP_CLUSTER_NAME_PROPERTY_ID),
+        (String) properties.get(SERVICE_GROUP_SERVICE_GROUP_NAME_PROPERTY_ID),
+        (String) properties.get(SERVICE_GROUP_SERVICE_GROUP_DISPLAY_NAME_PROPERTY_ID),
+        (String) properties.get(SERVICE_GROUP_SERVICE_GROUP_TYPE_PROPERTY_ID),
+        (String) properties.get(SERVICE_GROUP_ASSEMBLY_FILE_PROPERTY_ID),
+        (String) properties.get(SERVICE_GROUP_DESIRED_STATE_PROPERTY_ID),
+        (String) properties.get(SERVICE_GROUP_CURRENT_STATE_PROPERTY_ID));
+    return svcRequest;
+  }
+
+  // Create services from the given request.
+  public synchronized void createServiceGroups(Set<ServiceGroupRequest> requests)
+      throws AmbariException, AuthorizationException {
+
+    if (requests.isEmpty()) {
+      LOG.warn("Received an empty requests set");
+      return;
+    }
+    AmbariManagementController controller = getManagementController();
+    Clusters clusters = controller.getClusters();
+    for(ServiceGroupRequest request: requests) {
+      if(StringUtils.isBlank(request.getServiceGroupDisplayName())) {
+        request.setServiceGroupDisplayName(request.getServiceGroupName());
+      }
+    }
+
+    // do all validation checks
+    validateCreateRequests(requests, clusters);
+
+    ServiceGroupFactory serviceGroupFactory = controller.getServiceGroupFactory();
+    ServiceFactory serviceFactory = getManagementController().getServiceFactory();
+    ServiceComponentFactory serviceComponentFactory = getManagementController().getServiceComponentFactory();
+    for (ServiceGroupRequest request : requests) {
+      Cluster cluster = clusters.getCluster(request.getClusterName());
+
+      State desiredState = State.INIT;
+      State currentState = State.INIT;
+      if (!request.getServiceGroupType().equalsIgnoreCase("AMBARI")) {
+        ServiceGroupCacheKey cacheKey = new ServiceGroupCacheKey(request.getServiceGroupName());
+        ServiceGroupCacheValue cacheValue = null;
+        try {
+          cacheValue = cache.getServiceGroupCacheValue(cacheKey);
+        } catch (Exception e) {
+          LOG.error("Hit exception when retrieving service group from cache. Exception: " + e.getMessage());
+        }
+        if (cacheValue != null) {
+          // YarnApp already deployed (Ambari takeover)
+          desiredState = State.STARTED;
+          currentState = State.STARTED;
+        }
+      }
+      // Already checked that service group does not exist
+      ServiceGroup sg = serviceGroupFactory.createNew(cluster, request.getServiceGroupName(),
+          request.getServiceGroupDisplayName(), request.getServiceGroupType(), request.getAssemblyFile(), desiredState, currentState);
+      sg.persist();
+
+      try {
+        if (!request.getServiceGroupType().equalsIgnoreCase("AMBARI")) {
+          Map<String, Map<String, Integer>> serviceComponentsMap = parseAssemblyFile(request.getAssemblyFile(), cluster);
+          if (serviceComponentsMap != null) {
+            for (Map.Entry<String, Map<String, Integer>> serviceEntry : serviceComponentsMap.entrySet()) {
+              String stackServiceName = serviceEntry.getKey();
+              String serviceName = stackServiceName + "_" + request.getServiceGroupName();
+              LOG.info("Creating service " + serviceName + " in service group " + request.getServiceGroupName());
+              State state = State.INIT;
+              // Already checked that service does not exist
+              Service s = serviceFactory.createNew(
+                  cluster, serviceName, stackServiceName, request.getServiceGroupName());
+              s.setDesiredState(state);
+              s.setDesiredStackVersion(cluster.getDesiredStackVersion());
+              cluster.addService(s);
+              s.persist();
+              LOG.info("Created service " + serviceName + " in service group " + request.getServiceGroupName());
+
+              for (Map.Entry<String, Integer> componentEntry : serviceEntry.getValue().entrySet()) {
+                String componentName = componentEntry.getKey();
+                Integer desiredCount = componentEntry.getValue();
+                LOG.info("Creating service component " + componentName +
+                    " in service " + serviceName +
+                    " with desired count " + desiredCount);
+                ServiceComponent sc = serviceComponentFactory.createNew(s, componentName);
+                sc.setDesiredState(s.getDesiredState());
+                sc.setDesiredCount(desiredCount);
+                s.addServiceComponent(sc);
+                sc.persist();
+                LOG.info("Created service component " + componentName +
+                    " in service " + serviceName +
+                    " with desired count " + desiredCount);
+              }
+            }
+          }
+        }
+      } catch (Exception e) {
+        LOG.error("Failed to create service components for service group " + sg.getName());
+        LOG.error("Ignoring Exception : " + e.getMessage());
+      }
+    }
+  }
+
+  // Get services from the given set of requests.
+  protected Set<ServiceGroupResponse> getServiceGroups(Set<ServiceGroupRequest> requests)
+      throws AmbariException {
+    Set<ServiceGroupResponse> response = new HashSet<ServiceGroupResponse>();
+    for (ServiceGroupRequest request : requests) {
+      try {
+        response.addAll(getServiceGroups(request));
+      } catch (ServiceGroupNotFoundException e) {
+        if (requests.size() == 1) {
+          // only throw exception if 1 request.
+          // there will be > 1 request in case of OR predicate
+          throw e;
+        }
+      }
+    }
+    return response;
+  }
+
+  // Get services from the given request.
+  private Set<ServiceGroupResponse> getServiceGroups(ServiceGroupRequest request)
+      throws AmbariException {
+    if (request.getClusterName() == null
+        || request.getClusterName().isEmpty()) {
+      throw new AmbariException("Invalid arguments, cluster name"
+          + " cannot be null");
+    }
+    AmbariManagementController controller = getManagementController();
+    Clusters clusters    = controller.getClusters();
+    String   clusterName = request.getClusterName();
+
+    final Cluster cluster;
+    try {
+      cluster = clusters.getCluster(clusterName);
+    } catch (ObjectNotFoundException e) {
+      throw new ParentObjectNotFoundException("Parent Cluster resource doesn't exist", e);
+    }
+
+    Set<ServiceGroupResponse> response = new HashSet<>();
+    if (request.getServiceGroupName() != null) {
+      ServiceGroup sg = cluster.getServiceGroup(request.getServiceGroupName());
+      ServiceGroupResponse serviceGroupResponse = sg.convertToResponse();
+      if(sg != null && !sg.getServiceGroupType().equalsIgnoreCase("AMBARI")) {
+        ServiceGroupCacheKey cacheKey = new ServiceGroupCacheKey(sg.getName());
+        ServiceGroupCacheValue cacheValue = null;
+        try {
+          cacheValue = cache.getServiceGroupCacheValue(cacheKey);
+        } catch (Exception e) {
+          LOG.error("Hit exception when retrieving service group from cache. Exception: " + e.getMessage());
+        }
+        if(cacheValue != null) {
+          serviceGroupResponse.setApplicationId(cacheValue.getApplicationId());
+          serviceGroupResponse.setLifetime(cacheValue.getLifetime());
+          serviceGroupResponse.setQuickLinks(cacheValue.getQuicklinks());
+          serviceGroupResponse.setContainers(cacheValue.getContainers());
+          serviceGroupResponse.setNumContainers(cacheValue.getNumContainers());
+          serviceGroupResponse.setExpectedContainers(cacheValue.getExpectedContainers());
+        }
+      }
+      response.add(serviceGroupResponse);
+      return response;
+    }
+
+    for (ServiceGroup sg : cluster.getServiceGroups().values()) {
+      ServiceGroupResponse serviceGroupResponse = sg.convertToResponse();
+      if(!sg.getServiceGroupType().equalsIgnoreCase("AMBARI")) {
+        ServiceGroupCacheKey cacheKey = new ServiceGroupCacheKey(sg.getName());
+        ServiceGroupCacheValue cacheValue = null;
+        try {
+          cacheValue = cache.getServiceGroupCacheValue(cacheKey);
+        } catch (Exception e) {
+          LOG.error("Hit exception when retrieving service group from cache. Exception: " + e.getMessage());
+        }
+        if(cacheValue != null) {
+          serviceGroupResponse.setApplicationId(cacheValue.getApplicationId());
+          serviceGroupResponse.setLifetime(cacheValue.getLifetime());
+          serviceGroupResponse.setQuickLinks(cacheValue.getQuicklinks());
+          serviceGroupResponse.setContainers(cacheValue.getContainers());
+          serviceGroupResponse.setNumContainers(cacheValue.getNumContainers());
+          serviceGroupResponse.setExpectedContainers(cacheValue.getExpectedContainers());
+        }
+      }
+      response.add(serviceGroupResponse);
+    }
+    return response;
+  }
+
+
+  // Delete services based on the given set of requests
+  protected RequestStatusResponse deleteServiceGroups(Set<ServiceGroupRequest> request)
+      throws AmbariException, AuthorizationException {
+
+    Clusters clusters    = getManagementController().getClusters();
+
+    Set<ServiceGroup> removable = new HashSet<>();
+
+    for (ServiceGroupRequest serviceGroupRequest : request) {
+      if (StringUtils.isEmpty(serviceGroupRequest.getClusterName())
+          || StringUtils.isEmpty(serviceGroupRequest.getServiceGroupName())) {
+        // FIXME throw correct error
+        throw new AmbariException("invalid arguments");
+      } else {
+
+        if(!AuthorizationHelper.isAuthorized(
+            ResourceType.CLUSTER, getClusterResourceId(serviceGroupRequest.getClusterName()),
+            RoleAuthorization.SERVICE_ADD_DELETE_SERVICES)) {
+          throw new AuthorizationException("The user is not authorized to delete service groups");
+        }
+
+        ServiceGroup serviceGroup = clusters.getCluster(
+            serviceGroupRequest.getClusterName()).getServiceGroup(
+            serviceGroupRequest.getServiceGroupName());
+
+        // TODO: Add check to validate there are no services in the service group
+        removable.add(serviceGroup);
+      }
+    }
+
+    for (ServiceGroup serviceGroup : removable) {
+      serviceGroup.getCluster().deleteServiceGroup(serviceGroup.getName());
+    }
+
+    return null;
+  }
+
+
+  private void validateCreateRequests(Set<ServiceGroupRequest> requests, Clusters clusters)
+          throws AuthorizationException, AmbariException {
+
+    AmbariMetaInfo ambariMetaInfo = getManagementController().getAmbariMetaInfo();
+    Map<String, Set<String>> serviceGroupNames = new HashMap<>();
+    Set<String> duplicates = new HashSet<>();
+    for (ServiceGroupRequest request : requests) {
+      final String clusterName = request.getClusterName();
+      final String serviceGroupName = request.getServiceGroupName();
+
+      Validate.notEmpty(clusterName, "Cluster name should be provided when creating a service group");
+      Validate.notEmpty(serviceGroupName, "Service group name should be provided when creating a service group");
+
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Received a createServiceGroup request"
+            + ", clusterName=" + ", serviceGroupName=" + serviceGroupName + ", request=" + request);
+      }
+
+      if(!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER,
+          getClusterResourceId(clusterName), RoleAuthorization.SERVICE_ADD_DELETE_SERVICES)) {
+        throw new AuthorizationException("The user is not authorized to create service groups");
+      }
+
+      if (!serviceGroupNames.containsKey(clusterName)) {
+        serviceGroupNames.put(clusterName, new HashSet<String>());
+      }
+
+      if (serviceGroupNames.get(clusterName).contains(serviceGroupName)) {
+        // throw error later for dup
+        duplicates.add(serviceGroupName);
+        continue;
+      }
+      serviceGroupNames.get(clusterName).add(serviceGroupName);
+
+      Cluster cluster;
+      try {
+        cluster = clusters.getCluster(clusterName);
+      } catch (ClusterNotFoundException e) {
+        throw new ParentObjectNotFoundException("Attempted to add a service group to a cluster which doesn't exist", e);
+      }
+      try {
+        ServiceGroup sg = cluster.getServiceGroup(serviceGroupName);
+        if (sg != null) {
+          // throw error later for dup
+          duplicates.add(serviceGroupName);
+          continue;
+        }
+      } catch (ServiceGroupNotFoundException e) {
+        // Expected
+      }
+    }
+    // ensure only a single cluster update
+    if (serviceGroupNames.size() != 1) {
+      throw new IllegalArgumentException("Invalid arguments, updates allowed"
+              + "on only one cluster at a time");
+    }
+
+    // Validate dups
+    if (!duplicates.isEmpty()) {
+      String clusterName = requests.iterator().next().getClusterName();
+      String msg = "Attempted to create a service group which already exists: "
+              + ", clusterName=" + clusterName  + " serviceGroupName=" + StringUtils.join(duplicates, ",");
+
+      throw new DuplicateResourceException(msg);
+    }
+  }
+
+  private Map<String, Map<String, Integer>> parseAssemblyFile(String assemblyFile, Cluster cluster) throws AmbariException {
+    StackId stackId = cluster.getDesiredStackVersion();
+    AmbariMetaInfo ambariMetaInfo = getManagementController().getAmbariMetaInfo();
+    if(StringUtils.isBlank(assemblyFile)) {
+      return null;
+    }
+    Map<String, Map<String, Integer>> serviceComponentsMap = new HashMap<>();
+    Map<String, Object> assemblyMap = gson.fromJson(assemblyFile,
+        new TypeToken<Map<String, Object>>() {
+        }.getType());
+    if(assemblyMap != null && assemblyMap.containsKey("components")) {
+      for (Map<String, Object> componentMap : (ArrayList<Map<String, Object>>) assemblyMap.get("components")) {
+        if(componentMap.containsKey("name")) {
+          String stackComponentName = null;
+          String stackServiceName = null;
+          Integer desiredCount = 0;
+          String assemblyComponentName = (String)componentMap.get("name");
+          for(Map.Entry<String, String> componentEntry : componentNameMappings.entrySet()) {
+            if(componentEntry.getValue().equalsIgnoreCase(assemblyComponentName)) {
+              stackComponentName = componentEntry.getKey();
+              break;
+            }
+          }
+          if(stackComponentName != null) {
+            stackServiceName =
+                ambariMetaInfo.getComponentToService(stackId.getStackName(),
+                    stackId.getStackVersion(), stackComponentName);
+            if(componentMap.containsKey("number_of_containers")) {
+              desiredCount = ((Double)componentMap.get("number_of_containers")).intValue();
+            }
+          }
+          if(stackComponentName != null && stackServiceName != null) {
+            if(!serviceComponentsMap.containsKey(stackServiceName)) {
+              serviceComponentsMap.put(stackServiceName, new HashMap<String, Integer>());
+            }
+            Map<String, Integer> componentsMap = serviceComponentsMap.get(stackServiceName);
+            componentsMap.put(stackComponentName, desiredCount);
+          }
+        }
+      }
+    }
+    return serviceComponentsMap;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
index 56196c1..893cdb2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
@@ -89,6 +89,8 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
   // Services
   public static final String SERVICE_CLUSTER_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceInfo", "cluster_name");
   public static final String SERVICE_SERVICE_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceInfo", "service_name");
+  public static final String SERVICE_STACK_SERVICE_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceInfo", "stack_service_name");
+  public static final String SERVICE_SERVICE_GROUP_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("ServiceInfo", "service_group_name");
   public static final String SERVICE_SERVICE_STATE_PROPERTY_ID   = PropertyHelper.getPropertyId("ServiceInfo", "state");
   public static final String SERVICE_MAINTENANCE_STATE_PROPERTY_ID = PropertyHelper.getPropertyId("ServiceInfo", "maintenance_state");
 
@@ -109,7 +111,6 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
           SERVICE_CLUSTER_NAME_PROPERTY_ID,
           SERVICE_SERVICE_NAME_PROPERTY_ID}));
 
-
   private MaintenanceStateHelper maintenanceStateHelper;
 
   /**
@@ -192,6 +193,10 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
           response.getClusterName(), requestedIds);
       setResourceProperty(resource, SERVICE_SERVICE_NAME_PROPERTY_ID,
           response.getServiceName(), requestedIds);
+      setResourceProperty(resource, SERVICE_STACK_SERVICE_NAME_PROPERTY_ID,
+          response.getStackServiceName(), requestedIds);
+      setResourceProperty(resource, SERVICE_SERVICE_GROUP_NAME_PROPERTY_ID,
+          response.getServiceGroupName(), requestedIds);
       setResourceProperty(resource, SERVICE_SERVICE_STATE_PROPERTY_ID,
           calculateServiceState(response.getClusterName(), response.getServiceName()),
           requestedIds);
@@ -199,7 +204,7 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
           response.getMaintenanceState(), requestedIds);
 
       Map<String, Object> serviceSpecificProperties = getServiceSpecificProperties(
-          response.getClusterName(), response.getServiceName(), requestedIds);
+          response.getClusterName(), response.getServiceName(), response.getStackServiceName(), requestedIds);
 
       for (Map.Entry<String, Object> entry : serviceSpecificProperties.entrySet()) {
         setResourceProperty(resource, entry.getKey(), entry.getValue(), requestedIds);
@@ -322,6 +327,8 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
     ServiceRequest svcRequest = new ServiceRequest(
         (String) properties.get(SERVICE_CLUSTER_NAME_PROPERTY_ID),
         (String) properties.get(SERVICE_SERVICE_NAME_PROPERTY_ID),
+        (String) properties.get(SERVICE_STACK_SERVICE_NAME_PROPERTY_ID),
+        (String) properties.get(SERVICE_SERVICE_GROUP_NAME_PROPERTY_ID),
         (String) properties.get(SERVICE_SERVICE_STATE_PROPERTY_ID));
 
     Object o = properties.get(SERVICE_MAINTENANCE_STATE_PROPERTY_ID);
@@ -341,6 +348,14 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
       return;
     }
     Clusters clusters = getManagementController().getClusters();
+    for(ServiceRequest request: requests) {
+      if(StringUtils.isBlank(request.getStackServiceName())) {
+        request.setStackServiceName(request.getServiceName());
+      }
+      if(StringUtils.isBlank(request.getServiceGroupName())) {
+        request.setServiceGroupName("CORE");
+      }
+    }
     // do all validation checks
     validateCreateRequests(requests, clusters);
 
@@ -351,7 +366,8 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
       State state = State.INIT;
 
       // Already checked that service does not exist
-      Service s = serviceFactory.createNew(cluster, request.getServiceName());
+      Service s = serviceFactory.createNew(
+          cluster, request.getServiceName(), request.getStackServiceName(), request.getServiceGroupName());
 
       s.setDesiredState(state);
       s.setDesiredStackVersion(cluster.getDesiredStackVersion());
@@ -848,9 +864,10 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
    * @param serviceName  service name
    * @param requestedIds relevant request property ids
    */
-  private Map<String, Object> getServiceSpecificProperties(String clusterName, String serviceName, Set<String> requestedIds) {
+  private Map<String, Object> getServiceSpecificProperties(String clusterName, String serviceName,
+                                                           String stackServiceName, Set<String> requestedIds) {
     Map<String, Object> serviceSpecificProperties = new HashMap<String, Object>();
-    if (serviceName.equals("KERBEROS")) {
+    if (stackServiceName.equals("KERBEROS")) {
       // Only include details on whether the KDC administrator credentials are set and correct if
       // implicitly (Service/attributes) or explicitly (Service/attributes/kdc_...) queried
       if (requestedIds.contains(SERVICE_ATTRIBUTES_PROPERTY_ID) ||
@@ -895,15 +912,22 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
     for (ServiceRequest request : requests) {
       final String clusterName = request.getClusterName();
       final String serviceName = request.getServiceName();
+      final String stackServiceName = request.getStackServiceName();
+      final String serviceGroupName = request.getServiceGroupName();
+
       Validate.notEmpty(clusterName, "Cluster name should be provided when creating a service");
       Validate.notEmpty(serviceName, "Service name should be provided when creating a service");
+      Validate.notEmpty(stackServiceName, "Stack service name should be provided when creating a service");
+      Validate.notEmpty(serviceGroupName, "Service group name should be provided when creating a service");
 
       if (LOG.isDebugEnabled()) {
         LOG.debug("Received a createService request"
-                + ", clusterName=" + clusterName + ", serviceName=" + serviceName + ", request=" + request);
+            + ", clusterName=" + clusterName + ", serviceName=" + serviceName + ", stackServiceName=" + stackServiceName
+            + ", serviceGroupName=" + serviceGroupName + ", request=" + request);
       }
 
-      if(!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, getClusterResourceId(clusterName), RoleAuthorization.SERVICE_ADD_DELETE_SERVICES)) {
+      if(!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER,
+          getClusterResourceId(clusterName), RoleAuthorization.SERVICE_ADD_DELETE_SERVICES)) {
         throw new AuthorizationException("The user is not authorized to create services");
       }
 
@@ -946,7 +970,7 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
 
       StackId stackId = cluster.getDesiredStackVersion();
       if (!ambariMetaInfo.isValidService(stackId.getStackName(),
-              stackId.getStackVersion(), request.getServiceName())) {
+              stackId.getStackVersion(), request.getStackServiceName())) {
         throw new IllegalArgumentException("Unsupported or invalid service in stack, clusterName=" + clusterName
                 + ", serviceName=" + serviceName + ", stackInfo=" + stackId.getStackId());
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
index b8ed215..bdb1087 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
@@ -352,7 +352,7 @@ public class ViewInstanceResourceProvider extends AbstractAuthorizedResourceProv
     }
 
     if (properties.containsKey(CLUSTER_HANDLE_PROPERTY_ID)) {
-      viewInstanceEntity.setClusterHandle((String) properties.get(CLUSTER_HANDLE_PROPERTY_ID));
+      viewInstanceEntity.setClusterHandle(Long.valueOf((String) properties.get(CLUSTER_HANDLE_PROPERTY_ID)));
     }
 
     if (properties.containsKey(CLUSTER_TYPE_PROPERTY_ID)) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCache.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCache.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCache.java
new file mode 100644
index 0000000..84bb32a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCache.java
@@ -0,0 +1,124 @@
+/**
+ * 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.ambari.server.controller.servicegroup.cache;
+
+import net.sf.ehcache.CacheException;
+import net.sf.ehcache.Ehcache;
+import net.sf.ehcache.Element;
+import net.sf.ehcache.constructs.blocking.LockTimeoutException;
+import net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory;
+import net.sf.ehcache.constructs.blocking.UpdatingSelfPopulatingCache;
+import net.sf.ehcache.statistics.StatisticsGateway;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.SocketTimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.Map;
+
+public class ServiceGroupCache extends UpdatingSelfPopulatingCache {
+
+  private final static Logger LOG = LoggerFactory.getLogger(ServiceGroupCache.class);
+  private static AtomicInteger printCacheStatsCounter = new AtomicInteger(0);
+
+  /**
+   * Creates a SelfPopulatingCache.
+   *
+   * @param cache @Cache
+   * @param factory @CacheEntryFactory
+   */
+  public ServiceGroupCache(Ehcache cache, UpdatingCacheEntryFactory factory) throws CacheException {
+    super(cache, factory);
+  }
+
+
+
+  public ServiceGroupCacheValue getServiceGroupCacheValue(ServiceGroupCacheKey key)
+      throws IllegalArgumentException, IOException {
+
+    LOG.debug("Fetching service group cache value with key: " + key);
+    // Make sure key is valid
+    validateKey(key);
+
+    Element element = null;
+    try {
+      element = get(key);
+    } catch (LockTimeoutException le) {
+      // Ehcache masks the Socket Timeout to look as a LockTimeout
+      Throwable t = le.getCause();
+      if (t instanceof CacheException) {
+        t = t.getCause();
+        if (t instanceof SocketTimeoutException) {
+          throw new SocketTimeoutException(t.getMessage());
+        }
+      }
+    }
+
+    ServiceGroupCacheValue cacheValue = null;
+    if (element != null && element.getObjectValue() != null) {
+      cacheValue = (ServiceGroupCacheValue) element.getObjectValue();
+      LOG.debug("Returning service group value from cache: " + cacheValue);
+    }
+    return cacheValue;
+  }
+
+  public Map<String, Object> getResponseFromCache(ServiceGroupCacheKey key) throws IllegalArgumentException, IOException {
+    LOG.debug("Fetching service group with key: " + key);
+
+    // Make sure key is valid
+    validateKey(key);
+
+    Element element = null;
+    try {
+      element = get(key);
+    } catch (LockTimeoutException le) {
+      // Ehcache masks the Socket Timeout to look as a LockTimeout
+      Throwable t = le.getCause();
+      if (t instanceof CacheException) {
+        t = t.getCause();
+        if (t instanceof SocketTimeoutException) {
+          throw new SocketTimeoutException(t.getMessage());
+        }
+      }
+    }
+
+    Map<String, Object> response = null;
+    if (element != null && element.getObjectValue() != null) {
+      ServiceGroupCacheValue value = (ServiceGroupCacheValue) element.getObjectValue();
+      LOG.debug("Returning service group value from cache: " + value);
+      response = value.getResponse();
+    }
+    return response;
+  }
+
+
+  private void validateKey(ServiceGroupCacheKey key) throws IllegalArgumentException {
+    StringBuilder msg = new StringBuilder("Invalid service group key requested.");
+    boolean throwException = false;
+
+    if (key.getServiceGroupName() == null) {
+      msg.append(" No service group name provided.");
+      throwException = true;
+    }
+
+    if (throwException) {
+      throw new IllegalArgumentException(msg.toString());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheEntryFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheEntryFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheEntryFactory.java
new file mode 100644
index 0000000..718243c
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheEntryFactory.java
@@ -0,0 +1,102 @@
+/**
+ * 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.ambari.server.controller.servicegroup.cache;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import net.sf.ehcache.constructs.blocking.UpdatingCacheEntryFactory;
+import org.apache.ambari.server.configuration.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import java.util.Map;
+import org.apache.commons.io.IOUtils;
+
+@Singleton
+public class ServiceGroupCacheEntryFactory implements UpdatingCacheEntryFactory {
+  private final static Logger LOG = LoggerFactory.getLogger(ServiceGroupCacheEntryFactory.class);
+  private final String dashEndpoint;
+  private final Gson gson;
+
+  @Inject
+  public ServiceGroupCacheEntryFactory(Configuration configuration) {
+    gson = new Gson();
+    dashEndpoint = configuration.getDashApiEndpoint();
+  }
+
+  @Override
+  public Object createEntry(Object key) throws Exception {
+    LOG.debug("Creating cache entry since none exists, key = " + key);
+    ServiceGroupCacheKey serviceGroupCacheKey = (ServiceGroupCacheKey) key;
+
+    Map<String, Object> response = null;
+    String urlString = dashEndpoint + "/" +  serviceGroupCacheKey.getServiceGroupName().toLowerCase();
+    try {
+      URL url = new URL(urlString);
+      HttpURLConnection httpRequest = (HttpURLConnection) url.openConnection();
+      InputStream inputStream = httpRequest.getInputStream();
+      String jsonResponse = IOUtils.toString(inputStream, "UTF-8");
+      response = gson.fromJson(jsonResponse, new TypeToken<Map<String, Object>>() {
+      }.getType());
+    } catch (Exception e) {
+      LOG.error("Failed to get response from DASH endpoint " + dashEndpoint + "Exception : " + e.getMessage());
+      response = null;
+    }
+    ServiceGroupCacheValue value = null;
+    if (response != null) {
+      value = new ServiceGroupCacheValue(System.currentTimeMillis(), response);
+      LOG.debug("Created cache entry: " + value);
+    }
+    return value;
+  }
+
+  @Override
+  public void updateEntryValue(Object key, Object value) throws Exception {
+    ServiceGroupCacheKey serviceGroupCacheKey = (ServiceGroupCacheKey) key;
+    ServiceGroupCacheValue existingValue = (ServiceGroupCacheValue) value;
+    long fetchTime = existingValue.getFetchTime();
+    if(System.currentTimeMillis() - fetchTime > 60000) {
+      LOG.debug("Updating service group cache entry for key = " + key);
+      Map<String, Object> response = null;
+      String urlString = dashEndpoint + "/" +  serviceGroupCacheKey.getServiceGroupName().toLowerCase();
+      try {
+        URL url = new URL(urlString);
+        HttpURLConnection httpRequest = (HttpURLConnection) url.openConnection();
+        InputStream inputStream = httpRequest.getInputStream();
+        String jsonResponse = IOUtils.toString(inputStream, "UTF-8");
+        response = gson.fromJson(jsonResponse, new TypeToken<Map<String, Object>>() {
+        }.getType());
+      } catch (Exception e) {
+        LOG.error("Failed to get response from Dash endpoint " + dashEndpoint + "Exception : " + e.getMessage());
+        response = null;
+      }
+      if (response != null) {
+        existingValue.setFetchTime(System.currentTimeMillis());
+        existingValue.setResponse(response);
+        LOG.debug("Updated cache entry for key = " + key + ", newValue = " + value);
+      }
+    } else {
+      LOG.debug("Skipping updating service group cache entry for key = " + key);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheKey.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheKey.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheKey.java
new file mode 100644
index 0000000..b45e870
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheKey.java
@@ -0,0 +1,55 @@
+/**
+ * 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.ambari.server.controller.servicegroup.cache;
+
+public class ServiceGroupCacheKey {
+  private String serviceGroupName;
+
+  public ServiceGroupCacheKey(String serviceGroupName) {
+    this.serviceGroupName = serviceGroupName;
+  }
+
+  public String getServiceGroupName() {
+    return serviceGroupName;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ServiceGroupCacheKey that = (ServiceGroupCacheKey) o;
+
+    if (!serviceGroupName.equals(that.serviceGroupName))
+      return false;
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = serviceGroupName.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "ServiceGroupCacheKey { " +
+      "serviceGroupName=" + serviceGroupName +
+      " }";
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheProvider.java
new file mode 100644
index 0000000..2571216
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheProvider.java
@@ -0,0 +1,114 @@
+/**
+ * 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.ambari.server.controller.servicegroup.cache;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.config.CacheConfiguration;
+import net.sf.ehcache.config.PersistenceConfiguration;
+import net.sf.ehcache.config.SizeOfPolicyConfiguration;
+import net.sf.ehcache.config.SizeOfPolicyConfiguration.MaxDepthExceededBehavior;
+import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
+import org.apache.ambari.server.configuration.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static net.sf.ehcache.config.PersistenceConfiguration.Strategy;
+
+@Singleton
+public class ServiceGroupCacheProvider {
+  private ServiceGroupCache serviceGroupCache;
+  private volatile boolean isCacheInitialized = false;
+  public static final String SERVICE_GROUP_CACHE_MANAGER_NAME = "ServiceGroupCacheManager";
+  public static final String SERVICE_GROUP_CACHE_INSTANCE_NAME = "ServiceGroupCache";
+
+  Configuration configuration;
+  ServiceGroupCacheEntryFactory cacheEntryFactory;
+  private final static Logger LOG = LoggerFactory.getLogger(ServiceGroupCacheProvider.class);
+
+  @Inject
+  public ServiceGroupCacheProvider(Configuration configuration,
+                                     ServiceGroupCacheEntryFactory cacheEntryFactory) {
+    this.configuration = configuration;
+    this.cacheEntryFactory = cacheEntryFactory;
+  }
+
+  private synchronized void initializeCache() {
+    // Check in case of contention to avoid ObjectExistsException
+    if (isCacheInitialized) {
+      return;
+    }
+
+    System.setProperty("net.sf.ehcache.skipUpdateCheck", "true");
+
+    net.sf.ehcache.config.Configuration managerConfig =
+      new net.sf.ehcache.config.Configuration();
+    managerConfig.setName(SERVICE_GROUP_CACHE_MANAGER_NAME);
+
+    // Set max heap available to the cache manager
+    managerConfig.setMaxBytesLocalHeap("10%");
+
+    //Create a singleton CacheManager using defaults
+    CacheManager manager = CacheManager.create(managerConfig);
+
+    // TODO: Add service group cache timeout configs
+    LOG.info("Creating service group cache with timeouts => ttl = " +
+      configuration.getMetricCacheTTLSeconds() + ", idle = " +
+      configuration.getMetricCacheIdleSeconds());
+
+    // Create a Cache specifying its configuration.
+    CacheConfiguration cacheConfiguration = createCacheConfiguration();
+    Cache cache = new Cache(cacheConfiguration);
+
+    // Decorate with UpdatingSelfPopulatingCache
+    serviceGroupCache = new ServiceGroupCache(cache, cacheEntryFactory);
+
+    LOG.info("Registering service group cache with provider: name = " +
+      cache.getName() + ", guid: " + cache.getGuid());
+    manager.addCache(serviceGroupCache);
+    isCacheInitialized = true;
+  }
+
+  // Having this as a separate public method for testing/mocking purposes
+  public CacheConfiguration createCacheConfiguration() {
+
+    CacheConfiguration cacheConfiguration = new CacheConfiguration()
+      .name(SERVICE_GROUP_CACHE_INSTANCE_NAME)
+      .timeToLiveSeconds(configuration.getMetricCacheTTLSeconds()) // 1 hour
+      .timeToIdleSeconds(configuration.getMetricCacheIdleSeconds()) // 5 minutes
+      .memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU)
+      .sizeOfPolicy(new SizeOfPolicyConfiguration() // Set sizeOf policy to continue on max depth reached - avoid OOM
+        .maxDepth(10000)
+        .maxDepthExceededBehavior(MaxDepthExceededBehavior.CONTINUE))
+      .eternal(false)
+      .persistence(new PersistenceConfiguration()
+        .strategy(Strategy.NONE.name()));
+
+    return cacheConfiguration;
+  }
+
+  public ServiceGroupCache getServiceGroupCache() {
+    if (!isCacheInitialized) {
+      initializeCache();
+    }
+    return serviceGroupCache;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheValue.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheValue.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheValue.java
new file mode 100644
index 0000000..690c47a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/servicegroup/cache/ServiceGroupCacheValue.java
@@ -0,0 +1,135 @@
+/**
+ * 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.ambari.server.controller.servicegroup.cache;
+
+
+import java.util.Map;
+import java.util.ArrayList;
+
+/**
+ * Wrapper object for service group cache value.
+ */
+public class ServiceGroupCacheValue {
+  private long fetchTime;
+  private Map<String, Object> response = null;
+  private String applicationId = null;
+  private String state;
+  private String lifetime = null;
+  private Map<String, String> quicklinks = null;
+  private Integer numContainers;
+  private Integer expectedContainers;
+  public ArrayList<Map<String, Object>> containers = null;
+
+
+  public ServiceGroupCacheValue(long fetchTime, Map<String, Object>  response) {
+    this.fetchTime = fetchTime;
+    this.response = response;
+    parseResponse();
+  }
+
+  public Map<String, Object> getResponse() {
+    return response;
+  }
+
+  public void setResponse(Map<String, Object> response) {
+    this.response = response;
+    parseResponse();
+  }
+
+  public Long getFetchTime() {
+    return fetchTime;
+  }
+
+  public void setFetchTime(Long fetchTime) {
+    this.fetchTime = fetchTime;
+  }
+
+  public String getApplicationId() {
+    return applicationId;
+  }
+
+  public String getState() {
+    return state;
+  }
+
+  public Map<String, String> getQuicklinks() {
+    return quicklinks;
+  }
+
+  public Integer getNumContainers() {
+    return numContainers;
+  }
+
+  public Integer getExpectedContainers() {
+    return expectedContainers;
+  }
+
+  public String getLifetime() {
+    return lifetime;
+  }
+
+  public ArrayList<Map<String, Object>> getContainers() {
+    return containers;
+  }
+
+  public void parseResponse() {
+    if(response != null) {
+      if(response.containsKey("id")) {
+        applicationId = (String) response.get("id");
+      }
+
+      if(response.containsKey("quicklinks")) {
+        quicklinks = (Map<String, String>) response.get("quicklinks");
+      }
+
+      if(response.containsKey("state")) {
+        state = (String) response.get("state");
+      }
+
+      if(response.containsKey("lifetime")) {
+        lifetime = (String) response.get("lifetime");
+      }
+
+      if(response.containsKey("number_of_containers")) {
+        numContainers = ((Double) response.get("number_of_containers")).intValue();
+      }
+
+      if(response.containsKey("expected_number_of_containers")) {
+        expectedContainers = ((Double) response.get("expected_number_of_containers")).intValue();
+      }
+
+      if(response.containsKey("containers")) {
+        containers = (ArrayList<Map<String, Object>>) response.get("containers");
+
+      }
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "ServiceGroupCacheValue { " +
+        "fetchTime=" + fetchTime +
+        ", applicationId=" + applicationId +
+        ", state=" + state +
+        ", quicklinks=" + quicklinks +
+        ", lifetime=" + lifetime +
+        ", numContainers=" + numContainers +
+        ", expectedContainers=" + expectedContainers +
+        " }";
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index 99e4ccd..7e6fb09 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -76,6 +76,7 @@ public interface Resource {
   enum InternalType {
     Cluster,
     Service,
+    ServiceGroup,
     Setting,
     Host,
     Component,
@@ -194,6 +195,7 @@ public interface Resource {
      */
     public static final Type Cluster = InternalType.Cluster.getType();
     public static final Type Service = InternalType.Service.getType();
+    public static final Type ServiceGroup = InternalType.ServiceGroup.getType();
     public static final Type Setting = InternalType.Setting.getType();
     public static final Type Host = InternalType.Host.getType();
     public static final Type Component = InternalType.Component.getType();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/DatabaseChecker.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/DatabaseChecker.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/DatabaseChecker.java
index d35fc1a..436258f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/DatabaseChecker.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/DatabaseChecker.java
@@ -88,8 +88,8 @@ public class DatabaseChecker {
         if (serviceDesiredStateEntity == null) {
           checkPassed = false;
           LOG.error(String.format("ServiceDesiredStateEntity is null for " +
-              "ServiceComponentDesiredStateEntity, clusterName=%s, serviceName=%s ",
-            clusterEntity.getClusterName(), clusterServiceEntity.getServiceName()));
+              "ServiceComponentDesiredStateEntity, clusterName=%s, serviceName=%s, stackServiceName=%s ",
+            clusterEntity.getClusterName(), clusterServiceEntity.getServiceName(), clusterServiceEntity.getStackServiceName()));
         }
         Collection<ServiceComponentDesiredStateEntity> scDesiredStateEntities =
           clusterServiceEntity.getServiceComponentDesiredStateEntities();
@@ -97,8 +97,8 @@ public class DatabaseChecker {
           scDesiredStateEntities.isEmpty()) {
           checkPassed = false;
           LOG.error(String.format("serviceComponentDesiredStateEntities is null or empty for " +
-              "ServiceComponentDesiredStateEntity, clusterName=%s, serviceName=%s ",
-            clusterEntity.getClusterName(), clusterServiceEntity.getServiceName()));
+              "ServiceComponentDesiredStateEntity, clusterName=%s, serviceName=%s, stackServiceName=%s ",
+            clusterEntity.getClusterName(), clusterServiceEntity.getServiceName(), clusterServiceEntity.getStackServiceName()));
         } else {
           for (ServiceComponentDesiredStateEntity scDesiredStateEnity : scDesiredStateEntities) {
 
@@ -227,22 +227,24 @@ public class DatabaseChecker {
             for (ClusterServiceEntity clusterServiceEntity : clusterServiceEntities) {
               if (!State.INIT.equals(clusterServiceEntity.getServiceDesiredStateEntity().getDesiredState())) {
                 String serviceName = clusterServiceEntity.getServiceName();
-                ServiceInfo serviceInfo = ambariMetaInfo.getService(stack.getName(), stack.getVersion(), serviceName);
+                String stackServiceName = clusterServiceEntity.getStackServiceName();
+                String serviceGroupName = clusterServiceEntity.getServiceGroupName();
+                ServiceInfo serviceInfo = ambariMetaInfo.getService(stack.getName(), stack.getVersion(), stackServiceName);
                 for (String configTypeName : serviceInfo.getConfigTypeAttributes().keySet()) {
                   if (selectedCountForType.get(configTypeName) == null) {
                     checkPassed = false;
-                    LOG.error("ClusterConfigMapping does not contain mapping for service=" + serviceName + " type_name="
-                        + configTypeName);
+                    LOG.error("ClusterConfigMapping does not contain mapping for serviceName=" + serviceName
+                        + " stackServiceName=" + stackServiceName +  " serviceGroupName=" + serviceGroupName + " type_name=" + configTypeName);
                   } else {
                     // Check that for each config type exactly one is selected
                     if (selectedCountForType.get(configTypeName) == 0) {
                       checkPassed = false;
-                      LOG.error("ClusterConfigMapping selected count is 0 for service=" + serviceName + " type_name="
-                          + configTypeName);
+                      LOG.error("ClusterConfigMapping selected count is 0 for serviceName=" + serviceName
+                          + " stackServiceName=" + stackServiceName +  " serviceGroupName=" + serviceGroupName + " type_name=" + configTypeName);
                     } else if (selectedCountForType.get(configTypeName) > 1) {
                       checkPassed = false;
-                      LOG.error("ClusterConfigMapping selected count is more than 1 for service=" + serviceName
-                          + " type_name=" + configTypeName);
+                      LOG.error("ClusterConfigMapping selected count is more than 1 for serviceName=" + serviceName
+                          + " stackServiceName=" + stackServiceName +  " serviceGroupName=" + serviceGroupName + " type_name="+ configTypeName);
                     }
                   }
                 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
index 1079806..d91da98 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariEvent.java
@@ -38,6 +38,16 @@ public abstract class AmbariEvent {
     SERVICE_REMOVED_SUCCESS,
 
     /**
+     * A service group was successfully installed.
+     */
+    SERVICE_GROUP_INSTALL_SUCCESS,
+
+    /**
+     * A service group was successfully removed.
+     */
+    SERVICE_GROUP_REMOVED_SUCCESS,
+
+    /**
      * A service component was successfully installed.
      */
     SERVICE_COMPONENT_INSTALL_SUCCESS,

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentInstalledEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentInstalledEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentInstalledEvent.java
index 3ad1492..7e60980 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentInstalledEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentInstalledEvent.java
@@ -37,11 +37,11 @@ public class ServiceComponentInstalledEvent extends ServiceEvent {
    * @param hostName
    */
   public ServiceComponentInstalledEvent(long clusterId, String stackName,
-      String stackVersion, String serviceName, String componentName,
+      String stackVersion, String serviceName, String stackServiceName, String serviceGroupName, String componentName,
       String hostName, boolean recoveryEnabled) {
     super(AmbariEventType.SERVICE_COMPONENT_INSTALL_SUCCESS, clusterId,
         stackName,
-        stackVersion, serviceName);
+        stackVersion, serviceName, stackServiceName, serviceGroupName);
 
     m_componentName = componentName;
     m_hostName = hostName;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentUninstalledEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentUninstalledEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentUninstalledEvent.java
index 6f3fa95..822d325 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentUninstalledEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentUninstalledEvent.java
@@ -33,15 +33,16 @@ public class ServiceComponentUninstalledEvent extends ServiceEvent {
    * @param stackName
    * @param stackVersion
    * @param serviceName
+   * @param serviceGroupName
    * @param componentName
    * @param hostName
    */
   public ServiceComponentUninstalledEvent(long clusterId, String stackName,
-      String stackVersion, String serviceName, String componentName,
+      String stackVersion, String serviceName, String stackServiceName, String serviceGroupName, String componentName,
       String hostName, boolean recoveryEnabled) {
     super(AmbariEventType.SERVICE_COMPONENT_UNINSTALLED_SUCCESS, clusterId,
         stackName,
-        stackVersion, serviceName);
+        stackVersion, serviceName, stackServiceName, serviceGroupName);
 
     m_componentName = componentName;
     m_hostName = hostName;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java
index 3bc5c17..837e299 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceEvent.java
@@ -29,6 +29,16 @@ public abstract class ServiceEvent extends ClusterEvent {
   protected final String m_serviceName;
 
   /**
+   * The name of the real service.
+   */
+  protected final String m_stackServiceName;
+
+  /**
+   * The name of the service group.
+   */
+  protected final String m_serviceGroupName;
+
+  /**
    * The name of the services' stack.
    */
   protected final String m_stackName;
@@ -44,12 +54,14 @@ public abstract class ServiceEvent extends ClusterEvent {
    * @param eventType
    * @param clusterId
    */
-  public ServiceEvent(AmbariEventType eventType, long clusterId,
-      String stackName, String stackVersion, String serviceName) {
+  public ServiceEvent(AmbariEventType eventType, long clusterId, String stackName, String stackVersion,
+                      String serviceName, String stackServiceName, String serviceGroupName) {
     super(eventType, clusterId);
     m_stackName = stackName;
     m_stackVersion = stackVersion;
     m_serviceName = serviceName;
+    m_stackServiceName = stackServiceName;
+    m_serviceGroupName = serviceGroupName;
   }
 
   /**
@@ -60,6 +72,20 @@ public abstract class ServiceEvent extends ClusterEvent {
   }
 
   /**
+   * @return the stackServiceName (never {@code null}).
+   */
+  public String getStackServiceName() {
+    return m_stackServiceName;
+  }
+
+  /**
+   * @return the service group name (never {@code null}).
+   */
+  public String getServiceGroupName() {
+    return m_serviceGroupName;
+  }
+
+  /**
    * @return the stackName (never {@code null}).
    */
   public String getStackName() {


[29/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupEvent.java
new file mode 100644
index 0000000..9ff7eb9
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupEvent.java
@@ -0,0 +1,49 @@
+/**
+ * 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.ambari.server.events;
+
+
+/**
+ * The {@link ServiceEvent} class is the base for all service events in Ambari.
+ */
+public abstract class ServiceGroupEvent extends ClusterEvent {
+
+  /**
+   * The name of the service group.
+   */
+  protected final String m_serviceGroupName;
+
+   /**
+   * Constructor.
+   *
+   * @param eventType
+   * @param clusterId
+   */
+  public ServiceGroupEvent(AmbariEventType eventType, long clusterId, String serviceGroupName) {
+    super(eventType, clusterId);
+    m_serviceGroupName = serviceGroupName;
+  }
+
+  /**
+   * @return the service group name (never {@code null}).
+   */
+  public String getServiceGroupName() {
+    return m_serviceGroupName;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupInstalledEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupInstalledEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupInstalledEvent.java
new file mode 100644
index 0000000..71a6ab8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupInstalledEvent.java
@@ -0,0 +1,46 @@
+/**
+ * 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.ambari.server.events;
+
+/**
+ * The {@link ServiceGroupInstalledEvent} class is fired when a service group is
+ * successfully installed.
+ */
+public class ServiceGroupInstalledEvent extends ServiceGroupEvent {
+  /**
+   * Constructor.
+   *
+   * @param clusterId
+   * @param serviceGroupName
+   */
+  public ServiceGroupInstalledEvent(long clusterId, String serviceGroupName) {
+    super(AmbariEventType.SERVICE_GROUP_INSTALL_SUCCESS, clusterId, serviceGroupName);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString() {
+    StringBuilder buffer = new StringBuilder("ServiceGroupInstalledEvent{");
+    buffer.append("cluserId=").append(m_clusterId);
+    buffer.append(", serviceGroupName=").append(m_serviceGroupName);
+    buffer.append("}");
+    return buffer.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupRemovedEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupRemovedEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupRemovedEvent.java
new file mode 100644
index 0000000..45923a0
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceGroupRemovedEvent.java
@@ -0,0 +1,46 @@
+/**
+ * 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.ambari.server.events;
+
+/**
+ * The {@link ServiceRemovedEvent} class is fired when a service is successfully
+ * removed.
+ */
+public class ServiceGroupRemovedEvent extends ServiceGroupEvent {
+  /**
+   * Constructor.
+   *
+   * @param clusterId
+  * @param serviceGroupName
+   */
+  public ServiceGroupRemovedEvent(long clusterId, String serviceGroupName) {
+    super(AmbariEventType.SERVICE_GROUP_REMOVED_SUCCESS, clusterId, serviceGroupName);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString() {
+    StringBuilder buffer = new StringBuilder("ServiceGroupRemovedEvent{");
+    buffer.append("cluserId=").append(m_clusterId);
+    buffer.append(", serviceGroupName=").append(m_serviceGroupName);
+    buffer.append("}");
+    return buffer.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceInstalledEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceInstalledEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceInstalledEvent.java
index bd5799d..0475ad9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceInstalledEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceInstalledEvent.java
@@ -31,9 +31,9 @@ public class ServiceInstalledEvent extends ServiceEvent {
    * @param serviceName
    */
   public ServiceInstalledEvent(long clusterId, String stackName,
-      String stackVersion, String serviceName) {
+      String stackVersion, String serviceName, String stackServiceName, String serviceGroupName) {
     super(AmbariEventType.SERVICE_INSTALL_SUCCESS, clusterId, stackName,
-        stackVersion, serviceName);
+        stackVersion, serviceName, stackServiceName, serviceGroupName);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceRemovedEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceRemovedEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceRemovedEvent.java
index 7de2749..4df1651 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceRemovedEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceRemovedEvent.java
@@ -31,9 +31,9 @@ public class ServiceRemovedEvent extends ServiceEvent {
    * @param serviceName
    */
   public ServiceRemovedEvent(long clusterId, String stackName,
-      String stackVersion, String serviceName) {
+      String stackVersion, String serviceName, String stackServiceName, String serviceGroupName) {
     super(AmbariEventType.SERVICE_REMOVED_SUCCESS, clusterId, stackName,
-        stackVersion, serviceName);
+        stackVersion, serviceName, stackServiceName, serviceGroupName);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterServiceGroupDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterServiceGroupDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterServiceGroupDAO.java
new file mode 100644
index 0000000..efae45d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterServiceGroupDAO.java
@@ -0,0 +1,93 @@
+/**
+ * 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.ambari.server.orm.dao;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+
+import org.apache.ambari.server.orm.RequiresSession;
+import org.apache.ambari.server.orm.entities.ClusterServiceGroupEntity;
+import org.apache.ambari.server.orm.entities.ClusterServiceGroupEntityPK;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+
+@Singleton
+public class ClusterServiceGroupDAO {
+  @Inject
+  Provider<EntityManager> entityManagerProvider;
+  @Inject
+  DaoUtils daoUtils;
+
+  @RequiresSession
+  public ClusterServiceGroupEntity findByPK(ClusterServiceGroupEntityPK clusterServiceGroupEntityPK) {
+    return entityManagerProvider.get().find(ClusterServiceGroupEntity.class, clusterServiceGroupEntityPK);
+  }
+
+  @RequiresSession
+  public ClusterServiceGroupEntity findByClusterAndServiceGroupNames(String  clusterName, String serviceGroupName) {
+    TypedQuery<ClusterServiceGroupEntity> query = entityManagerProvider.get()
+        .createNamedQuery("clusterServiceGroupByClusterAndServiceGroupNames", ClusterServiceGroupEntity.class);
+    query.setParameter("clusterName", clusterName);
+    query.setParameter("serviceGroupName", serviceGroupName);
+
+    try {
+      return query.getSingleResult();
+    } catch (NoResultException ignored) {
+      return null;
+    }
+  }
+
+  @RequiresSession
+  public List<ClusterServiceGroupEntity> findAll() {
+    return daoUtils.selectAll(entityManagerProvider.get(), ClusterServiceGroupEntity.class);
+  }
+
+  @Transactional
+  public void refresh(ClusterServiceGroupEntity clusterServiceGroupEntity) {
+    entityManagerProvider.get().refresh(clusterServiceGroupEntity);
+  }
+
+  @Transactional
+  public void create(ClusterServiceGroupEntity clusterServiceGroupEntity) {
+    entityManagerProvider.get().persist(clusterServiceGroupEntity);
+  }
+
+  @Transactional
+  public ClusterServiceGroupEntity merge(ClusterServiceGroupEntity clusterServiceGroupEntity) {
+    return entityManagerProvider.get().merge(clusterServiceGroupEntity);
+  }
+
+  @Transactional
+  public void remove(ClusterServiceGroupEntity clusterServiceGroupEntity) {
+    entityManagerProvider.get().remove(merge(clusterServiceGroupEntity));
+  }
+
+  @Transactional
+  public void removeByPK(ClusterServiceGroupEntityPK clusterServiceGroupEntityPK) {
+    ClusterServiceGroupEntity entity = findByPK(clusterServiceGroupEntityPK);
+    entityManagerProvider.get().remove(entity);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RemoteAmbariClusterDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RemoteAmbariClusterDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RemoteAmbariClusterDAO.java
index 72ab368..e817aff 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RemoteAmbariClusterDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RemoteAmbariClusterDAO.java
@@ -72,6 +72,19 @@ public class RemoteAmbariClusterDAO {
   }
 
   /**
+   * Find Cluster by Id
+   * @param clusterId
+   * @return
+   */
+  @RequiresSession
+  public RemoteAmbariClusterEntity findById(Long clusterId) {
+    TypedQuery<RemoteAmbariClusterEntity> query = entityManagerProvider.get().
+      createNamedQuery("remoteAmbariClusterById", RemoteAmbariClusterEntity.class);
+    query.setParameter("clusterId", clusterId);
+    return daoUtils.selectSingle(query);
+  }
+
+  /**
    * Save a Cluster entity
    * @param entity
      */

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntity.java
index bf0faee..54d4d63 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterConfigEntity.java
@@ -71,6 +71,9 @@ public class ClusterConfigEntity {
   @Column(name = "type_name")
   private String type;
 
+  @Column(name = "stack_type_name")
+  private String stackType;
+
   @Column(name = "version")
   private Long version;
 
@@ -131,6 +134,14 @@ public class ClusterConfigEntity {
     type = typeName;
   }
 
+  public String getStackType() {
+    return stackType;
+  }
+
+  public void setStackType(String stackTypeName) {
+    stackType = stackTypeName;
+  }
+
   public Long getVersion() {
     return version;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java
index 2e0a15d..1875bbd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterEntity.java
@@ -106,6 +106,9 @@ public class ClusterEntity {
   @OneToMany(mappedBy = "clusterEntity")
   private Collection<ClusterServiceEntity> clusterServiceEntities;
 
+  @OneToMany(mappedBy = "clusterEntity")
+  private Collection<ClusterServiceGroupEntity> clusterServiceGroupEntities;
+
   @OneToOne(mappedBy = "clusterEntity", cascade = CascadeType.REMOVE)
   private ClusterStateEntity clusterStateEntity;
 
@@ -268,6 +271,14 @@ public class ClusterEntity {
     this.clusterServiceEntities = clusterServiceEntities;
   }
 
+  public Collection<ClusterServiceGroupEntity> getClusterServiceGroupEntities() {
+    return clusterServiceGroupEntities;
+  }
+
+  public void setClusterServiceGroupEntities(Collection<ClusterServiceGroupEntity> clusterServiceGroupEntities) {
+    this.clusterServiceGroupEntities = clusterServiceGroupEntities;
+  }
+
   public ClusterStateEntity getClusterStateEntity() {
     return clusterStateEntity;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceEntity.java
index 320c1be..56f42ff 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceEntity.java
@@ -41,6 +41,12 @@ public class ClusterServiceEntity {
   @Column(name = "service_name", nullable = false, insertable = true, updatable = true)
   private String serviceName;
 
+  @Column(name = "stack_service_name", nullable = false, insertable = true, updatable = true)
+  private String stackServiceName;
+
+  @Column(name = "service_group_name", nullable = false, insertable = true, updatable = true)
+  private String serviceGroupName;
+
   @Basic
   @Column(name = "service_enabled", nullable = false, insertable = true, updatable = true, length = 10)
   private Integer serviceEnabled = 0;
@@ -71,6 +77,22 @@ public class ClusterServiceEntity {
     this.serviceName = serviceName;
   }
 
+  public String getStackServiceName() {
+    return stackServiceName;
+  }
+
+  public void setStackServiceName(String stackServiceName) {
+    this.stackServiceName = stackServiceName;
+  }
+
+  public String getServiceGroupName() {
+    return serviceGroupName;
+  }
+
+  public void setServiceGroupName(String serviceGroupName) {
+    this.serviceGroupName = serviceGroupName;
+  }
+
   public int getServiceEnabled() {
     return serviceEnabled;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceGroupEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceGroupEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceGroupEntity.java
new file mode 100644
index 0000000..8f2d97e
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceGroupEntity.java
@@ -0,0 +1,153 @@
+/**
+ * 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.ambari.server.orm.entities;
+
+import org.apache.ambari.server.state.State;
+
+import javax.persistence.*;
+import java.util.Collection;
+
+@javax.persistence.IdClass(ClusterServiceGroupEntityPK.class)
+@javax.persistence.Table(name = "clusterservicegroups")
+@NamedQueries({
+    @NamedQuery(name = "clusterServiceGroupByClusterAndServiceGroupNames", query =
+        "SELECT clusterServiceGroup " +
+            "FROM ClusterServiceGroupEntity clusterServiceGroup " +
+            "JOIN clusterServiceGroup.clusterEntity cluster " +
+            "WHERE clusterServiceGroup.serviceGroupName=:serviceGroupName AND cluster.clusterName=:clusterName")
+})
+@Entity
+public class ClusterServiceGroupEntity {
+
+  @Id
+  @Column(name = "cluster_id", nullable = false, insertable = false, updatable = false, length = 10)
+  private Long clusterId;
+
+  @Id
+  @Column(name = "service_group_name", nullable = false, insertable = true, updatable = true)
+  private String serviceGroupName;
+
+  @Column(name = "service_group_display_name", nullable = false, insertable = true, updatable = true)
+  private String serviceGroupDisplayName;
+
+  @ManyToOne
+  @JoinColumn(name = "cluster_id", referencedColumnName = "cluster_id", nullable = false)
+  private ClusterEntity clusterEntity;
+
+  @Column(name = "service_group_type", nullable = false, insertable = true, updatable = true)
+  private String serviceGroupType;
+
+  @Lob
+  @Column(name = "assembly_file", nullable = true, insertable = true, updatable = true)
+  private String assemblyFile;
+
+  @Column(name = "current_state", nullable = false, insertable = true, updatable = true)
+  @Enumerated(value = EnumType.STRING)
+  private State currentState = State.INIT;
+
+  @Column(name = "desired_state", nullable = false, insertable = true, updatable = true)
+  @Enumerated(value = EnumType.STRING)
+  private State desiredState = State.INIT;
+
+  public Long getClusterId() {
+    return clusterId;
+  }
+
+  public void setClusterId(Long clusterId) {
+    this.clusterId = clusterId;
+  }
+
+
+  public String getServiceGroupName() {
+    return serviceGroupName;
+  }
+
+  public void setServiceGroupName(String serviceGroupName) {
+    this.serviceGroupName = serviceGroupName;
+  }
+
+  public String getServiceGroupDisplayName() {
+    return serviceGroupDisplayName;
+  }
+
+  public void setServiceGroupDisplayName(String serviceGroupDisplayName) {
+    this.serviceGroupDisplayName = serviceGroupDisplayName;
+  }
+
+  public String getServiceGroupType() {
+    return serviceGroupType;
+  }
+
+  public void setServiceGroupType(String serviceGroupType) {
+    this.serviceGroupType = serviceGroupType;
+  }
+
+  public String getAssemblyFile() {
+    return assemblyFile;
+  }
+
+  public void setAssemblyFile(String assemblyFile) {
+    this.assemblyFile = assemblyFile;
+  }
+
+  public State getDesiredState() {
+    return desiredState;
+  }
+
+  public void setDesiredState(State desiredState) {
+    this.desiredState = desiredState;
+  }
+
+  public State getCurrentState() {
+    return currentState;
+  }
+
+  public void setCurrentState(State currentState) {
+    this.currentState = currentState;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ClusterServiceGroupEntity that = (ClusterServiceGroupEntity) o;
+
+    if (clusterId != null ? !clusterId.equals(that.clusterId) : that.clusterId != null) return false;
+    if (serviceGroupName != null ? !serviceGroupName.equals(that.serviceGroupName) : that.serviceGroupName != null) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = clusterId !=null ? clusterId.intValue() : 0;
+    result = 31 * result + (serviceGroupName != null ? serviceGroupName.hashCode() : 0);
+    return result;
+  }
+
+  public ClusterEntity getClusterEntity() {
+    return clusterEntity;
+  }
+
+  public void setClusterEntity(ClusterEntity clusterEntity) {
+    this.clusterEntity = clusterEntity;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceGroupEntityPK.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceGroupEntityPK.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceGroupEntityPK.java
new file mode 100644
index 0000000..c9c565e
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceGroupEntityPK.java
@@ -0,0 +1,71 @@
+/**
+ * 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.ambari.server.orm.entities;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+import javax.persistence.Lob;
+import java.io.Serializable;
+
+@SuppressWarnings("serial")
+public class ClusterServiceGroupEntityPK implements Serializable {
+  private Long clusterId;
+
+  @Id
+  @Column(name = "cluster_id", nullable = false, insertable = true, updatable = true, length = 10)
+  public Long getClusterId() {
+    return clusterId;
+  }
+
+  public void setClusterId(Long clusterId) {
+    this.clusterId = clusterId;
+  }
+
+  private String serviceGroupName;
+
+  @Id
+  @Column(name = "service_group_name", nullable = false, insertable = true, updatable = true)
+  public String getServiceGroupName() {
+    return serviceGroupName;
+  }
+
+  public void setServiceGroupName(String serviceGroupName) {
+    this.serviceGroupName = serviceGroupName;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ClusterServiceGroupEntityPK that = (ClusterServiceGroupEntityPK) o;
+
+    if (clusterId != null ? !clusterId.equals(that.clusterId) : that.clusterId != null) return false;
+    if (serviceGroupName != null ? !serviceGroupName.equals(that.serviceGroupName) : that.serviceGroupName != null) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = clusterId !=null ? clusterId.intValue() : 0;
+    result = 31 * result + (serviceGroupName != null ? serviceGroupName.hashCode() : 0);
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterEntity.java
index 99c9f2a..48ca3f8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RemoteAmbariClusterEntity.java
@@ -53,7 +53,11 @@ import java.util.Collection;
   @NamedQuery(name = "remoteAmbariClusterByName", query =
     "SELECT remoteAmbariCluster " +
       "FROM RemoteAmbariClusterEntity remoteAmbariCluster " +
-      "WHERE remoteAmbariCluster.name=:clusterName")})
+      "WHERE remoteAmbariCluster.name=:clusterName"),
+  @NamedQuery(name = "remoteAmbariClusterById", query =
+    "SELECT remoteAmbariCluster " +
+      "FROM RemoteAmbariClusterEntity remoteAmbariCluster " +
+      "WHERE remoteAmbariCluster.id=:clusterId")})
 @Entity
 public class RemoteAmbariClusterEntity {
 
@@ -67,7 +71,7 @@ public class RemoteAmbariClusterEntity {
   @GeneratedValue(strategy = GenerationType.TABLE, generator = "remote_cluster_id_generator")
   private Long id;
 
-  @Column(name = "name", nullable = false, insertable = true, updatable = false)
+  @Column(name = "name", nullable = false, insertable = true, updatable = true)
   private String name;
 
   @Column(name = "url", nullable = false, insertable = true, updatable = true)

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
index 7281c01..464faf7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
@@ -84,6 +84,8 @@ public class ServiceComponentDesiredStateEntity {
   @Column(name = "recovery_enabled", nullable = false, insertable = true, updatable = true)
   private Integer recoveryEnabled = 0;
 
+  @Column(name = "desired_count", nullable = false, insertable = true, updatable = true)
+  private Integer desiredCount = 0;
   /**
    * Unidirectional one-to-one association to {@link StackEntity}
    */
@@ -169,6 +171,14 @@ public class ServiceComponentDesiredStateEntity {
     this.desiredVersion = desiredVersion;
   }
 
+  public int getDesiredCount() {
+    return desiredCount;
+  }
+
+  public void setDesiredCount(int desiredCount) {
+    this.desiredCount = desiredCount;
+  }
+
   /**
    * Adds a historical entry for the version of this service component. New
    * entries are automatically created when this entities is merged via a

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
index 98bafdd..e20db3b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
@@ -121,7 +121,7 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
    * The associated cluster handle.
    */
   @Column(name = "cluster_handle", nullable = true)
-  private String clusterHandle;
+  private Long clusterHandle;
 
   /**
    *  Cluster Type for cluster Handle
@@ -360,7 +360,7 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
   }
 
   @Override
-  public String getClusterHandle() {
+  public Long getClusterHandle() {
     return clusterHandle;
   }
 
@@ -443,11 +443,11 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
   /**
    * Set a cluster association for this view instance with the Ambari cluster
    * identified by the given cluster handle.  For a local cluster reference,
-   * the cluster handle is simply the unique cluster name.
+   * the cluster handle is simply the unique cluster id.
    *
    * @param clusterHandle  the cluster identifier
    */
-  public void setClusterHandle(String clusterHandle) {
+  public void setClusterHandle(Long clusterHandle) {
     this.clusterHandle = clusterHandle;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/serveraction/servicegroup/ServiceGroupServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/servicegroup/ServiceGroupServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/servicegroup/ServiceGroupServerAction.java
new file mode 100644
index 0000000..640a0b8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/servicegroup/ServiceGroupServerAction.java
@@ -0,0 +1,91 @@
+/*
+ * 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.ambari.server.serveraction.servicegroup;
+
+import com.google.gson.Gson;
+import com.google.inject.Inject;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.agent.ExecutionCommand;
+import org.apache.ambari.server.serveraction.AbstractServerAction;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public abstract class ServiceGroupServerAction extends AbstractServerAction {
+
+  protected final static Logger LOG = LoggerFactory.getLogger(ServiceGroupServerAction.class);
+
+  /**
+   * Gson
+   */
+  @Inject
+  protected Gson gson;
+
+  /**
+   * The Cluster that this ServerAction implementation is executing on
+   */
+  @Inject
+  private Clusters clusters = null;
+
+  /**
+   * Returns the relevant Cluster object
+   *
+   * @return the relevant Cluster
+   * @throws AmbariException if the Cluster object cannot be retrieved
+   */
+  protected Cluster getCluster() throws AmbariException {
+    Cluster cluster = clusters.getCluster(getClusterName());
+
+    if (cluster == null) {
+      throw new AmbariException(String.format("Failed to retrieve cluster for %s", getClusterName()));
+    }
+
+    return cluster;
+  }
+
+  /**
+   * The Clusters object for this KerberosServerAction
+   *
+   * @return a Clusters object
+   */
+  protected Clusters getClusters() {
+    return clusters;
+  }
+
+  /**
+   * Returns the relevant cluster's name
+   * <p/>
+   * Using the data from the execution command, retrieve the relevant cluster's name.
+   *
+   * @return a String declaring the relevant cluster's name
+   * @throws AmbariException if the cluster's name is not available
+   */
+  protected String getClusterName() throws AmbariException {
+    ExecutionCommand executionCommand = getExecutionCommand();
+    String clusterName = (executionCommand == null) ? null : executionCommand.getClusterName();
+
+    if ((clusterName == null) || clusterName.isEmpty()) {
+      throw new AmbariException("Failed to retrieve the cluster name from the execution command");
+    }
+
+    return clusterName;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/serveraction/servicegroup/YarnServiceGroupServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/servicegroup/YarnServiceGroupServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/servicegroup/YarnServiceGroupServerAction.java
new file mode 100644
index 0000000..57b113a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/servicegroup/YarnServiceGroupServerAction.java
@@ -0,0 +1,171 @@
+/*
+ * 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.ambari.server.serveraction.servicegroup;
+
+import com.google.gson.reflect.TypeToken;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.actionmanager.HostRoleStatus;
+import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.agent.ExecutionCommand;
+import org.apache.ambari.server.controller.ServiceComponentHostResponse;
+import org.apache.ambari.server.state.*;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+public class YarnServiceGroupServerAction extends ServiceGroupServerAction {
+  public static String COMMAND_PARAM_SERVICE_GROUP = "service_group";
+  public static String COMMAND_PARAM_DESIRED_STATE = "desired_state";
+  public static String COMMAND_PARAM_DASH_API_ENDPOINT = "dash_api_endpoint";
+
+  @Override
+  public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext) throws AmbariException, InterruptedException {
+
+    Cluster cluster = getCluster();
+    if(cluster == null) {
+      throw new AmbariException("Missing cluster object");
+    }
+    Map<String, String> commandParams = getCommandParameters();
+    if(commandParams == null) {
+      throw new AmbariException("Missing command params");
+    }
+    if(!commandParams.containsKey(COMMAND_PARAM_SERVICE_GROUP)) {
+      throw new AmbariException("Missing service group");
+    }
+    if(!commandParams.containsKey(COMMAND_PARAM_DESIRED_STATE)) {
+      throw new AmbariException("Missing desired state");
+    }
+    if(!commandParams.containsKey(COMMAND_PARAM_DASH_API_ENDPOINT)) {
+      throw new AmbariException("Missing Dash API endpoint");
+    }
+
+    String serviceGroupName = commandParams.get(COMMAND_PARAM_SERVICE_GROUP);
+    State desiredState = State.valueOf(commandParams.get(COMMAND_PARAM_DESIRED_STATE));
+    String dashApiEndpoint = commandParams.get(COMMAND_PARAM_DASH_API_ENDPOINT);
+
+    ServiceGroup sg = cluster.getServiceGroup(serviceGroupName);
+    String sgType = sg.getServiceGroupType();
+
+    if(!sgType.equalsIgnoreCase("YARN")) {
+      throw new AmbariException("Invalid service group type " + sgType);
+    }
+    if(StringUtils.isBlank(sg.getAssemblyFile())) {
+      throw new AmbariException("Assembly file contents not set");
+    }
+
+
+    actionLog.writeStdOut("=================================================");
+    actionLog.writeStdOut("Service Group : " + serviceGroupName);
+    actionLog.writeStdOut("Desired State : " + desiredState);
+    actionLog.writeStdOut("Dash API Endpoint : " + dashApiEndpoint);
+    actionLog.writeStdOut("=================================================");
+
+    if(desiredState == State.INSTALLED && sg.getCurrentState() == State.INIT) {
+      // Installing Service Group
+      actionLog.writeStdOut("Installing service group " + serviceGroupName);
+      try {
+        URL url = new URL(dashApiEndpoint);
+        HttpURLConnection httpRequest = (HttpURLConnection) url.openConnection();
+        httpRequest.setDoOutput(true);
+        httpRequest.setDoInput(true);
+        httpRequest.setRequestMethod("POST");
+        httpRequest.setRequestProperty("Content-Type", "application/json");
+        httpRequest.setRequestProperty("Content-Length", String.valueOf(sg.getAssemblyFile().length()));
+        httpRequest.setRequestProperty("Accept", "application/json");
+
+        OutputStream os = httpRequest.getOutputStream();
+        os.write(sg.getAssemblyFile().getBytes());
+        int responseCode = httpRequest.getResponseCode();
+        actionLog.writeStdOut("Dash response code = " + responseCode);
+        if (responseCode != 202) {
+          String errorMessage = "Failed to install service group " + serviceGroupName + " via Dash API endpoint " + dashApiEndpoint;
+          actionLog.writeStdErr(errorMessage);
+          throw new AmbariException(errorMessage);
+        }
+      } catch (Exception e) {
+        String errorMessage = "Hit exception while installing service group " + serviceGroupName + " via Dash API endpoint " + dashApiEndpoint;
+        actionLog.writeStdErr(errorMessage);
+        actionLog.writeStdErr("Exception = " + e.getMessage());
+        throw new AmbariException(errorMessage, e);
+      }
+      sg.setCurrentState(State.INSTALLED);
+      actionLog.writeStdOut("Service group " + serviceGroupName + " successfully installed");
+    } else if(desiredState == State.STARTED && sg.getCurrentState() == State.INSTALLED) {
+      // Starting service group
+      actionLog.writeStdOut("Waiting for service group " + serviceGroupName + " to start");
+      String urlString = dashApiEndpoint + "/" + serviceGroupName.toLowerCase();
+      Boolean started = false;
+      while(!started) {
+        try {
+          URL url = new URL(urlString);
+          HttpURLConnection httpRequest = (HttpURLConnection) url.openConnection();
+          InputStream inputStream = httpRequest.getInputStream();
+          String jsonResponse = IOUtils.toString(inputStream, "UTF-8");
+          actionLog.writeStdOut("*****************************************************");
+          actionLog.writeStdOut("Get Response:");
+          actionLog.writeStdOut(jsonResponse);
+          actionLog.writeStdOut("*****************************************************");
+          Map<String, Object> responseMap = gson.fromJson(jsonResponse, new TypeToken<Map<String, Object>>() {
+          }.getType());
+
+          if (responseMap != null && responseMap.containsKey("state") && responseMap.containsKey("containers")) {
+            started = true;
+            String appState = (String) responseMap.get("state");
+            if (appState.equalsIgnoreCase("RUNNING")) {
+              for (Map<String, String> cMap : (ArrayList<Map<String, String>>) responseMap.get("containers")) {
+                String containerState = cMap.get("state");
+                if (!containerState.equalsIgnoreCase("READY")) {
+                  started = false;
+                  break;
+                }
+              }
+            } else {
+              started = false;
+            }
+          }
+        } catch (Exception e) {
+          String errorMessage = "Hit exception while waiting for service group " + serviceGroupName + " to start via Dash API endpoint " + dashApiEndpoint;
+          actionLog.writeStdErr(errorMessage);
+          actionLog.writeStdErr("Exception = " + e.getMessage());
+          actionLog.writeStdErr("Will retry!");
+        }
+        if (!started) {
+          Thread.sleep(1000);
+        }
+      }
+      sg.setCurrentState(State.STARTED);
+      actionLog.writeStdOut("Service group " + serviceGroupName + " successfully started");
+    } else if(desiredState == State.INSTALLED && sg.getCurrentState() == State.STARTED) {
+      // Stopping service group
+      actionLog.writeStdOut("Stopping service group " + serviceGroupName);
+      sg.setCurrentState(State.INSTALLED);
+      actionLog.writeStdOut("Service group " + serviceGroupName + "successfully stopped");
+    }
+    sg.persist();
+    return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
index d9df8b4..5f64460 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
@@ -25,6 +25,7 @@ import java.util.Set;
 import java.util.concurrent.locks.ReadWriteLock;
 
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ServiceGroupNotFoundException;
 import org.apache.ambari.server.controller.ClusterResponse;
 import org.apache.ambari.server.controller.ServiceConfigVersionResponse;
 import org.apache.ambari.server.events.ClusterConfigChangedEvent;
@@ -68,6 +69,15 @@ public interface Cluster {
    */
   void addService(Service service);
 
+
+  /**
+   * Add service group to the cluster
+   * @param serviceGroup
+   * @return
+   * @throws AmbariException
+   */
+  void addServiceGroup(ServiceGroup serviceGroup);
+
   /**
    * Get a service
    * @param serviceName
@@ -82,6 +92,19 @@ public interface Cluster {
   Map<String, Service> getServices();
 
   /**
+   * Get a service group
+   * @param serviceGroupName
+   * @return
+   */
+  ServiceGroup getServiceGroup(String serviceGroupName) throws ServiceGroupNotFoundException;
+
+  /**
+   * Get all service groups
+   * @return
+   */
+  Map<String, ServiceGroup> getServiceGroups() throws AmbariException;
+
+  /**
    * Get all ServiceComponentHosts on a given host
    * @param hostname
    * @return
@@ -413,6 +436,8 @@ public interface Cluster {
 
   String getServiceForConfigTypes(Collection<String> configTypes);
 
+  String getStackConfigTypeFromConfigType(String configType);
+
   /**
    * Apply specified service config version (rollback)
    * @param serviceName service name
@@ -502,6 +527,19 @@ public interface Cluster {
   void deleteService(String serviceName) throws AmbariException;
 
   /**
+   * Delete all the service groups associated with this cluster
+   * @throws AmbariException
+   */
+  void deleteAllServiceGroups() throws AmbariException;
+
+  /**
+   * Delete the named service associated with this cluster
+   * @param serviceGroupName
+   * @throws AmbariException
+   */
+  void deleteServiceGroup(String serviceGroupName) throws AmbariException;
+
+  /**
    * Gets if the cluster can be deleted
    * @return
    */
@@ -516,10 +554,12 @@ public interface Cluster {
   /**
    * Add service to the cluster
    * @param serviceName
+   * @param stackServiceName
+   * @param serviceGroupName
    * @return
    * @throws AmbariException
    */
-  Service addService(String serviceName) throws AmbariException;
+  Service addService(String serviceName, String stackServiceName, String serviceGroupName) throws AmbariException;
 
   /**
    * Get lock to control access to cluster structure

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/Clusters.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Clusters.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Clusters.java
index e660d20..bd9de13 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Clusters.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Clusters.java
@@ -62,6 +62,14 @@ public interface Clusters {
       throws AmbariException;
 
   /**
+   * Gets the Cluster given the cluster id
+   * @param clusterId Id of the Cluster to retrieve
+   * @return  <code>Cluster</code> identified by the given id
+   */
+  Cluster getCluster(Long clusterId)
+    throws AmbariException;
+
+  /**
    * Get all clusters
    * @return <code>Map</code> of clusters with cluster name as key
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java
index b35aad9..f83f550 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java
@@ -38,6 +38,11 @@ public interface Config {
   public String getType();
 
   /**
+   * @return Stack Config Type
+   */
+  public String getStackType();
+
+  /**
    * @return Version Tag this config instance is mapped to
    */
   public String getTag();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java
index dbdd5a2..6bf725b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java
@@ -57,6 +57,7 @@ public class ConfigImpl implements Config {
   private Cluster cluster;
   private StackId stackId;
   private String type;
+  private String stackType;
   private volatile String tag;
   private volatile Long version;
   private volatile Map<String, String> properties;
@@ -81,6 +82,10 @@ public class ConfigImpl implements Config {
       @Assisted Map<String, Map<String, String>> propertiesAttributes, Injector injector) {
     this.cluster = cluster;
     this.type = type;
+    this.stackType = cluster.getStackConfigTypeFromConfigType(type);
+    if(StringUtils.isBlank(this.stackType)) {
+      this.stackType = type;
+    }
     this.properties = properties;
     this.propertiesAttributes = propertiesAttributes;
 
@@ -97,6 +102,7 @@ public class ConfigImpl implements Config {
   public ConfigImpl(@Assisted Cluster cluster, @Assisted ClusterConfigEntity entity, Injector injector) {
     this.cluster = cluster;
     type = entity.getType();
+    stackType = entity.getStackType();
     tag = entity.getTag();
     version = entity.getVersion();
 
@@ -168,7 +174,16 @@ public class ConfigImpl implements Config {
     } finally {
       readWriteLock.readLock().unlock();
     }
+  }
 
+  @Override
+  public String getStackType() {
+    readWriteLock.readLock().lock();
+    try {
+      return stackType;
+    } finally {
+      readWriteLock.readLock().unlock();
+    }
   }
 
   @Override
@@ -362,6 +377,7 @@ public class ConfigImpl implements Config {
           entity.setClusterEntity(clusterEntity);
           entity.setClusterId(cluster.getClusterId());
           entity.setType(getType());
+          entity.setStackType(getStackType());
           entity.setVersion(getVersion());
           entity.setTag(getTag());
           entity.setTimestamp(new Date().getTime());

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
index 7000574..ead72ca 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
@@ -28,6 +28,10 @@ public interface Service {
 
   String getName();
 
+  String getStackServiceName();
+
+  String getServiceGroupName();
+
   long getClusterId();
 
   Cluster getCluster();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java
index 983cbdf..643587f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java
@@ -44,6 +44,10 @@ public interface ServiceComponent {
 
   String getServiceName();
 
+  String getStackServiceName();
+
+  String getServiceGroupName();
+
   long getClusterId();
 
   String getClusterName();
@@ -60,6 +64,10 @@ public interface ServiceComponent {
 
   void setDesiredVersion(String version);
 
+  int getDesiredCount();
+
+  void setDesiredCount(int desiredCount);
+
   Map<String, ServiceComponentHost> getServiceComponentHosts();
 
   ServiceComponentHost getServiceComponentHost(String hostname)

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java
index 4866148..915d08a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentHost.java
@@ -46,6 +46,18 @@ public interface ServiceComponentHost {
   String getServiceName();
 
   /**
+   * Get the Real Service this object maps to
+   * @return Name of the Real Service
+   */
+  String getStackServiceName();
+
+  /**
+   * Get the service group name this object maps to
+   * @return Name of the service group
+   */
+  String getServiceGroupName();
+
+  /**
    * Get the ServiceComponent this object maps to
    * @return Name of the ServiceComponent
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
index 9283e38..c5ca4bf 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
@@ -18,16 +18,24 @@
 
 package org.apache.ambari.server.state;
 
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ObjectNotFoundException;
 import org.apache.ambari.server.ServiceComponentHostNotFoundException;
+import org.apache.ambari.server.ServiceGroupNotFoundException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.ServiceComponentHostResponse;
 import org.apache.ambari.server.controller.ServiceComponentResponse;
 import org.apache.ambari.server.events.ServiceComponentRecoveryChangedEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
@@ -43,6 +51,9 @@ import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
 import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.state.cluster.ClusterImpl;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.utils.MapUtils;
+import org.apache.commons.io.IOUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -139,7 +150,7 @@ public class ServiceComponentImpl implements ServiceComponent {
     StackId stackId = service.getDesiredStackVersion();
     try {
       ComponentInfo compInfo = ambariMetaInfo.getComponent(
-        stackId.getStackName(), stackId.getStackVersion(), service.getName(),
+        stackId.getStackName(), stackId.getStackVersion(), service.getStackServiceName(),
         componentName);
       isClientComponent = compInfo.isClient();
       isMasterComponent = compInfo.isMaster();
@@ -250,6 +261,16 @@ public class ServiceComponentImpl implements ServiceComponent {
   }
 
   @Override
+  public String getStackServiceName() {
+    return service.getStackServiceName();
+  }
+
+  @Override
+  public String getServiceGroupName() {
+    return service.getServiceGroupName();
+  }
+
+  @Override
   public long getClusterId() {
     return service.getClusterId();
   }
@@ -515,6 +536,33 @@ public class ServiceComponentImpl implements ServiceComponent {
   }
 
   @Override
+  public int getDesiredCount() {
+    readWriteLock.readLock().lock();
+    try {
+      return getDesiredStateEntity().getDesiredCount();
+    } finally {
+      readWriteLock.readLock().unlock();
+    }
+  }
+
+  @Override
+  public void setDesiredCount(int desiredCount) {
+    readWriteLock.writeLock().lock();
+    try {
+      ServiceComponentDesiredStateEntity desiredStateEntity = getDesiredStateEntity();
+      if (desiredStateEntity != null) {
+        desiredStateEntity.setDesiredCount(desiredCount);
+        saveIfPersisted(desiredStateEntity);
+      } else {
+        LOG.warn("Setting a member on an entity object that may have been " +
+            "previously deleted, serviceName = " + (service != null ? service.getName() : ""));
+      }
+    } finally {
+      readWriteLock.writeLock().unlock();
+    }
+  }
+
+  @Override
   public ServiceComponentResponse convertToResponse() {
     readWriteLock.readLock().lock();
     try {
@@ -522,7 +570,7 @@ public class ServiceComponentImpl implements ServiceComponent {
       ServiceComponentResponse r = new ServiceComponentResponse(getClusterId(),
           cluster.getClusterName(), service.getName(), getName(),
           getDesiredStackVersion().getStackId(), getDesiredState().toString(),
-          getTotalCount(), getStartedCount(), getInstalledCount(),
+          getTotalCount(), getStartedCount(), getInstalledCount(), getDesiredCount(),
           isRecoveryEnabled(), displayName);
       return r;
     } finally {
@@ -799,10 +847,19 @@ public class ServiceComponentImpl implements ServiceComponent {
   }
 
   private int getSCHCountByState(State state) {
+    Cluster cluster = service.getCluster();
+    ServiceGroup sg = null;
+    try {
+      sg = cluster.getServiceGroup(getServiceGroupName());
+    } catch (ServiceGroupNotFoundException e) {
+      sg = null;
+    }
     int count = 0;
+    if(sg == null || sg.getServiceGroupType().equalsIgnoreCase("AMBARI")) {
     for (ServiceComponentHost sch : hostComponents.values()) {
-      if (sch.getState() == state) {
-        count++;
+        if (sch.getState() == state) {
+          count++;
+        }
       }
     }
     return count;
@@ -817,7 +874,18 @@ public class ServiceComponentImpl implements ServiceComponent {
   }
 
   private int getTotalCount() {
-    return hostComponents.size();
+    Cluster cluster = service.getCluster();
+    ServiceGroup sg = null;
+    try {
+      sg = cluster.getServiceGroup(getServiceGroupName());
+    } catch (ServiceGroupNotFoundException e) {
+      sg = null;
+    }
+    if(sg == null || sg.getServiceGroupType().equalsIgnoreCase("AMBARI")) {
+      return hostComponents.size();
+    } else {
+      return getDesiredCount();
+    }
   }
 
   // Refresh cached reference after ever setter
@@ -825,7 +893,6 @@ public class ServiceComponentImpl implements ServiceComponent {
     if (!isPersisted()) {
       return desiredStateEntity;
     }
-
     return serviceComponentDesiredStateDAO.findById(desiredStateEntity.getId());
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceFactory.java
index a3a041b..16d0c7a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceFactory.java
@@ -18,11 +18,15 @@
 
 package org.apache.ambari.server.state;
 
+import com.google.inject.assistedinject.Assisted;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
 
 public interface ServiceFactory {
 
-  Service createNew(Cluster cluster, String serviceName);
+  Service createNew(Cluster cluster,
+                    @Assisted("serviceName") String serviceName,
+                    @Assisted("stackServiceName") String stackServiceName,
+                    @Assisted("serviceGroupName") String serviceGroupName);
 
   Service createExisting(Cluster cluster, ClusterServiceEntity serviceEntity);
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroup.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroup.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroup.java
new file mode 100644
index 0000000..df86b50
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroup.java
@@ -0,0 +1,79 @@
+/**
+ * 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.ambari.server.state;
+
+import java.util.Map;
+import java.util.concurrent.locks.ReadWriteLock;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.ServiceGroupResponse;
+
+public interface ServiceGroup {
+
+  String getName();
+
+  String getServiceGroupDisplayName();
+
+  void setServiceGroupDisplayName(String displayName);
+
+  String getServiceGroupType();
+
+  String getAssemblyFile();
+
+  void setAssemblyFile(String assemblyFile);
+
+  long getClusterId();
+
+  Cluster getCluster();
+
+  State getDesiredState();
+
+  void setDesiredState(State state);
+
+  State getCurrentState();
+
+  void setCurrentState(State state);
+
+  ServiceGroupResponse convertToResponse();
+
+  void debugDump(StringBuilder sb);
+
+  boolean isPersisted();
+
+  void persist();
+
+  void refresh();
+
+  /**
+   * Find out whether the service and its components
+   * are in a state that it can be removed from a cluster
+   * @return
+   */
+  boolean canBeRemoved();
+
+  void delete() throws AmbariException;
+
+  /**
+   * Get lock to control access to cluster structure
+   * @return cluster-global lock
+   */
+  ReadWriteLock getClusterGlobalLock();
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupFactory.java
new file mode 100644
index 0000000..5c4effa
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupFactory.java
@@ -0,0 +1,35 @@
+/**
+ * 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.ambari.server.state;
+
+import com.google.inject.assistedinject.Assisted;
+import org.apache.ambari.server.orm.entities.ClusterServiceGroupEntity;
+
+public interface ServiceGroupFactory {
+
+  ServiceGroup createNew(Cluster cluster,
+      @Assisted("serviceGroupName") String serviceGroupName,
+      @Assisted("serviceGroupDisplayName") String serviceGroupDisplayName,
+      @Assisted("serviceGroupType") String serviceGroupType,
+      @Assisted("assemblyFile") String assemblyFile,
+      @Assisted("desiredState") State desiredState,
+      @Assisted("currentState") State currentState);
+
+  ServiceGroup createExisting(Cluster cluster, ClusterServiceGroupEntity serviceGroupEntity);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
new file mode 100644
index 0000000..89fedb9
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
@@ -0,0 +1,378 @@
+/**
+ * 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.ambari.server.state;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.ProvisionException;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.ServiceGroupResponse;
+import org.apache.ambari.server.events.MaintenanceModeEvent;
+import org.apache.ambari.server.events.ServiceGroupInstalledEvent;
+import org.apache.ambari.server.events.ServiceGroupRemovedEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.orm.dao.ClusterDAO;
+import org.apache.ambari.server.orm.dao.ClusterServiceGroupDAO;
+import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
+import org.apache.ambari.server.orm.entities.ClusterConfigMappingEntity;
+import org.apache.ambari.server.orm.entities.ClusterEntity;
+import org.apache.ambari.server.orm.entities.ClusterServiceGroupEntity;
+import org.apache.ambari.server.orm.entities.ClusterServiceGroupEntityPK;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+
+public class ServiceGroupImpl implements ServiceGroup {
+  private final ReadWriteLock clusterGlobalLock;
+  private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
+  // Cached entity has only 1 getter for name
+  private ClusterServiceGroupEntity serviceGroupEntity;
+  private ClusterServiceGroupEntityPK serviceGroupEntityPK;
+
+  private static final Logger LOG = LoggerFactory.getLogger(ServiceImpl.class);
+
+  private volatile boolean persisted = false;
+  private final Cluster cluster;
+
+  @Inject
+  private ClusterServiceGroupDAO clusterServiceGroupDAO;
+  @Inject
+  private ClusterDAO clusterDAO;
+  @Inject
+  private AmbariMetaInfo ambariMetaInfo;
+
+  /**
+   * Used to publish events relating to service group CRUD operations.
+   */
+  @Inject
+  private AmbariEventPublisher eventPublisher;
+
+  private final Gson gson;
+  private Map<String, Object> responseMap = null;
+  private long lastFetchTimestamp = 0;
+
+  private void init() {
+    // TODO load from DB during restart?
+  }
+
+  @AssistedInject
+  public ServiceGroupImpl(@Assisted Cluster cluster,
+      @Assisted("serviceGroupName") String serviceGroupName,
+      @Assisted("serviceGroupDisplayName") String serviceGroupDisplayName,
+      @Assisted("serviceGroupType") String serviceGroupType,
+      @Assisted("assemblyFile") String assemblyFile,
+      @Assisted("desiredState") State desiredState,
+      @Assisted("currentState") State currentState,
+      Injector injector) throws AmbariException {
+    injector.injectMembers(this);
+    gson = injector.getInstance(Gson.class);
+
+    clusterGlobalLock = cluster.getClusterGlobalLock();
+    serviceGroupEntity = new ClusterServiceGroupEntity();
+    serviceGroupEntity.setClusterId(cluster.getClusterId());
+    serviceGroupEntity.setServiceGroupName(serviceGroupName);
+    serviceGroupEntity.setServiceGroupDisplayName(serviceGroupDisplayName);
+    serviceGroupEntity.setServiceGroupType(serviceGroupType);
+    serviceGroupEntity.setAssemblyFile(assemblyFile);
+    serviceGroupEntity.setDesiredState(desiredState);
+    serviceGroupEntity.setCurrentState(currentState);
+    this.cluster = cluster;
+    init();
+  }
+
+  private void populateResponseMap() {
+    Map<String, String> configs = ambariMetaInfo.getAmbariServerProperties();
+    String dashEndpoint = configs.containsKey(Configuration.YARN_DASH_API_ENDPOINT)?
+        configs.get(Configuration.YARN_DASH_API_ENDPOINT) : Configuration.YARN_DASH_API_ENDPOINT_DEFAULT;
+    String urlString = dashEndpoint + "/" +  getName().toLowerCase();
+    try {
+      URL url = new URL(urlString);
+      HttpURLConnection httpRequest = (HttpURLConnection) url.openConnection();
+      InputStream inputStream = httpRequest.getInputStream();
+      String jsonResponse = IOUtils.toString(inputStream, "UTF-8");
+      responseMap = gson.fromJson(jsonResponse, new TypeToken<Map<String, Object>>() {
+      }.getType());
+      lastFetchTimestamp = System.currentTimeMillis();
+    } catch (Exception e) {
+      LOG.error("Failed to get response from DASH endpoint " + dashEndpoint);
+      responseMap = null;
+    }
+  }
+
+  @AssistedInject
+  public ServiceGroupImpl(@Assisted Cluster cluster, @Assisted ClusterServiceGroupEntity
+      serviceGroupEntity, Injector injector) throws AmbariException {
+    injector.injectMembers(this);
+    gson = injector.getInstance(Gson.class);
+    clusterGlobalLock = cluster.getClusterGlobalLock();
+    this.serviceGroupEntity = serviceGroupEntity;
+    this.cluster = cluster;
+    persisted = true;
+  }
+
+  @Override
+  public ReadWriteLock getClusterGlobalLock() {
+    return clusterGlobalLock;
+  }
+
+  @Override
+  public String getName() {
+    return serviceGroupEntity.getServiceGroupName();
+  }
+
+  @Override
+  public String getServiceGroupDisplayName() {
+    return serviceGroupEntity.getServiceGroupDisplayName();
+  }
+
+  @Override
+  public void setServiceGroupDisplayName(String displayName) {
+    serviceGroupEntity.setServiceGroupDisplayName(displayName);
+  }
+
+  @Override
+  public String getServiceGroupType() {
+    return serviceGroupEntity.getServiceGroupType();
+  }
+
+  @Override
+  public String getAssemblyFile() {
+    return serviceGroupEntity.getAssemblyFile();
+  }
+
+  @Override
+  public void setAssemblyFile(String assemblyFile) {
+    serviceGroupEntity.setAssemblyFile(assemblyFile);
+  }
+
+  @Override
+  public long getClusterId() {
+    return cluster.getClusterId();
+  }
+
+  @Override
+  public State getDesiredState() {
+    return serviceGroupEntity.getDesiredState();
+  }
+
+  @Override
+  public void setDesiredState(State state) {
+    serviceGroupEntity.setDesiredState(state);
+  }
+
+  @Override
+  public State getCurrentState() {
+    return serviceGroupEntity.getCurrentState();
+  }
+
+  @Override
+  public void setCurrentState(State state) {
+    serviceGroupEntity.setCurrentState(state);
+  }
+
+  @Override
+  public ServiceGroupResponse convertToResponse() {
+    readWriteLock.readLock().lock();
+    try {
+      ServiceGroupResponse r = new ServiceGroupResponse(cluster.getClusterId(),
+          cluster.getClusterName(), getName(), getServiceGroupDisplayName(),
+          getServiceGroupType(), getAssemblyFile(), getDesiredState().toString(), getCurrentState().toString());
+      return r;
+    } finally {
+      readWriteLock.readLock().unlock();
+    }
+  }
+
+  @Override
+  public Cluster getCluster() {
+    return cluster;
+  }
+
+  @Override
+  public void debugDump(StringBuilder sb) {
+    readWriteLock.readLock().lock();
+    try {
+      sb.append("ServiceGroup={ serviceGroupName=" + getName()  + ", clusterName="
+          + cluster.getClusterName() + ", clusterId=" + cluster.getClusterId() + "}");
+    } finally {
+      readWriteLock.readLock().unlock();
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isPersisted() {
+    // a lock around this internal state variable is not required since we
+    // have appropriate locks in the persist() method and this member is
+    // only ever false under the condition that the object is new
+    return persisted;
+  }
+
+  /**
+   * {@inheritDoc}
+   * <p/>
+   * This method uses Java locks and then delegates to internal methods which
+   * perform the JPA merges inside of a transaction. Because of this, a
+   * transaction is not necessary before this calling this method.
+   */
+  @Override
+  public void persist() {
+    clusterGlobalLock.writeLock().lock();
+    try {
+      readWriteLock.writeLock().lock();
+      try {
+        if (!persisted) {
+          persistEntities();
+          refresh();
+          // There refresh calls are no longer needed with cached references
+          // not used on getters/setters
+          // cluster.refresh();
+          persisted = true;
+
+          // publish the service installed event
+          StackId stackId = cluster.getDesiredStackVersion();
+          cluster.addServiceGroup(this);
+
+          ServiceGroupInstalledEvent event = new ServiceGroupInstalledEvent(
+              getClusterId(), getName());
+          eventPublisher.publish(event);
+        } else {
+          saveIfPersisted();
+        }
+      } finally {
+        readWriteLock.writeLock().unlock();
+      }
+    } finally {
+      clusterGlobalLock.writeLock().unlock();
+    }
+  }
+
+  @Transactional
+  protected void persistEntities() {
+    long clusterId = cluster.getClusterId();
+
+    ClusterEntity clusterEntity = clusterDAO.findById(clusterId);
+    serviceGroupEntity.setClusterEntity(clusterEntity);
+    clusterServiceGroupDAO.create(serviceGroupEntity);
+    clusterEntity.getClusterServiceGroupEntities().add(serviceGroupEntity);
+    clusterDAO.merge(clusterEntity);
+    clusterServiceGroupDAO.merge(serviceGroupEntity);
+  }
+
+  @Transactional
+  void saveIfPersisted() {
+    if (isPersisted()) {
+      clusterServiceGroupDAO.merge(serviceGroupEntity);
+    }
+  }
+
+  @Override
+  @Transactional
+  public void refresh() {
+    readWriteLock.writeLock().lock();
+    try {
+      if (isPersisted()) {
+        ClusterServiceGroupEntityPK pk = new ClusterServiceGroupEntityPK();
+        pk.setClusterId(getClusterId());
+        pk.setServiceGroupName(getName());
+        serviceGroupEntity = clusterServiceGroupDAO.findByPK(pk);
+        clusterServiceGroupDAO.refresh(serviceGroupEntity);
+      }
+    } finally {
+      readWriteLock.writeLock().unlock();
+    }
+  }
+
+  @Override
+  public boolean canBeRemoved() {
+    clusterGlobalLock.readLock().lock();
+    try {
+      readWriteLock.readLock().lock();
+      try {
+        // TODO: Add check for services in the service group
+        return true;
+      } finally {
+        readWriteLock.readLock().unlock();
+      }
+    } finally {
+      clusterGlobalLock.readLock().unlock();
+    }
+  }
+
+
+  @Override
+  @Transactional
+  public void delete() throws AmbariException {
+    clusterGlobalLock.writeLock().lock();
+    try {
+      readWriteLock.writeLock().lock();
+      try {
+
+        if (persisted) {
+          removeEntities();
+          persisted = false;
+
+          // publish the service removed event
+          ServiceGroupRemovedEvent event = new ServiceGroupRemovedEvent(getClusterId(), getName());
+
+          eventPublisher.publish(event);
+        }
+      } finally {
+        readWriteLock.writeLock().unlock();
+      }
+    } finally {
+      clusterGlobalLock.writeLock().unlock();
+    }
+
+
+  }
+
+  @Transactional
+  protected void removeEntities() throws AmbariException {
+
+    ClusterServiceGroupEntityPK pk = new ClusterServiceGroupEntityPK();
+    pk.setClusterId(getClusterId());
+    pk.setServiceGroupName(getName());
+    clusterServiceGroupDAO.removeByPK(pk);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
index 3120b86..ce9c64c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
@@ -110,13 +110,16 @@ public class ServiceImpl implements Service {
   }
 
   @AssistedInject
-  public ServiceImpl(@Assisted Cluster cluster, @Assisted String serviceName,
+  public ServiceImpl(@Assisted Cluster cluster, @Assisted("serviceName") String serviceName,
+      @Assisted("stackServiceName") String stackServiceName, @Assisted("serviceGroupName") String serviceGroupName,
       Injector injector) throws AmbariException {
     injector.injectMembers(this);
     clusterGlobalLock = cluster.getClusterGlobalLock();
     serviceEntity = new ClusterServiceEntity();
     serviceEntity.setClusterId(cluster.getClusterId());
     serviceEntity.setServiceName(serviceName);
+    serviceEntity.setStackServiceName(stackServiceName);
+    serviceEntity.setServiceGroupName(serviceGroupName);
     serviceDesiredStateEntity = new ServiceDesiredStateEntity();
     serviceDesiredStateEntity.setServiceName(serviceName);
     serviceDesiredStateEntity.setClusterId(cluster.getClusterId());
@@ -135,7 +138,7 @@ public class ServiceImpl implements Service {
     setDesiredStackVersion(stackId);
 
     ServiceInfo sInfo = ambariMetaInfo.getService(stackId.getStackName(),
-        stackId.getStackVersion(), serviceName);
+        stackId.getStackVersion(), stackServiceName);
     isClientOnlyService = sInfo.isClientOnlyService();
 
     init();
@@ -165,9 +168,11 @@ public class ServiceImpl implements Service {
                     serviceComponentDesiredStateEntity));
           } catch(ProvisionException ex) {
             StackId stackId = cluster.getCurrentStackVersion();
-            LOG.error(String.format("Can not get component info: stackName=%s, stackVersion=%s, serviceName=%s, componentName=%s",
+            LOG.error(String.format("Can not get component info: stackName=%s, stackVersion=%s, serviceName=%s, " +
+                "stackServiceName=%s, componentName=%s",
                 stackId.getStackName(), stackId.getStackVersion(),
-                serviceEntity.getServiceName(),serviceComponentDesiredStateEntity.getComponentName()));
+                serviceEntity.getServiceName(), serviceEntity.getStackServiceName(),
+                serviceComponentDesiredStateEntity.getComponentName()));
             ex.printStackTrace();
           }
       }
@@ -175,7 +180,7 @@ public class ServiceImpl implements Service {
 
     StackId stackId = getDesiredStackVersion();
     ServiceInfo sInfo = ambariMetaInfo.getService(stackId.getStackName(),
-        stackId.getStackVersion(), getName());
+        stackId.getStackVersion(), getStackServiceName());
     isClientOnlyService = sInfo.isClientOnlyService();
 
     persisted = true;
@@ -192,6 +197,16 @@ public class ServiceImpl implements Service {
   }
 
   @Override
+  public String getStackServiceName() {
+    return serviceEntity.getStackServiceName();
+  }
+
+  @Override
+  public String getServiceGroupName() {
+    return serviceEntity.getServiceGroupName();
+  }
+
+  @Override
   public long getClusterId() {
     return cluster.getClusterId();
   }
@@ -236,6 +251,7 @@ public class ServiceImpl implements Service {
               + ", clusterName=" + cluster.getClusterName()
               + ", clusterId=" + cluster.getClusterId()
               + ", serviceName=" + getName()
+              + ", stackServiceName=" + getStackServiceName()
               + ", serviceComponentName=" + component.getName());
         }
         if (components.containsKey(component.getName())) {
@@ -243,6 +259,7 @@ public class ServiceImpl implements Service {
               + ", clusterName=" + cluster.getClusterName()
               + ", clusterId=" + cluster.getClusterId()
               + ", serviceName=" + getName()
+              + ", stackServiceName=" + getStackServiceName()
               + ", serviceComponentName=" + component.getName());
         }
         components.put(component.getName(), component);
@@ -266,6 +283,7 @@ public class ServiceImpl implements Service {
               + ", clusterName=" + cluster.getClusterName()
               + ", clusterId=" + cluster.getClusterId()
               + ", serviceName=" + getName()
+              + ", stackServiceName=" + getStackServiceName()
               + ", serviceComponentName=" + serviceComponentName);
         }
         if (components.containsKey(serviceComponentName)) {
@@ -273,6 +291,7 @@ public class ServiceImpl implements Service {
               + ", clusterName=" + cluster.getClusterName()
               + ", clusterId=" + cluster.getClusterId()
               + ", serviceName=" + getName()
+              + ", stackServiceName=" + getStackServiceName()
               + ", serviceComponentName=" + serviceComponentName);
         }
         ServiceComponent component = serviceComponentFactory.createNew(this, serviceComponentName);
@@ -293,7 +312,7 @@ public class ServiceImpl implements Service {
     try {
       if (!components.containsKey(componentName)) {
         throw new ServiceComponentNotFoundException(cluster.getClusterName(),
-            getName(), componentName);
+            getName(), getStackServiceName(), getServiceGroupName(), componentName);
       }
       return components.get(componentName);
     } finally {
@@ -318,7 +337,7 @@ public class ServiceImpl implements Service {
       if (LOG.isDebugEnabled()) {
         LOG.debug("Setting DesiredState of Service" + ", clusterName="
             + cluster.getClusterName() + ", clusterId="
-            + cluster.getClusterId() + ", serviceName=" + getName()
+            + cluster.getClusterId() + ", serviceName=" + getName() + ", stackServiceName=" + getStackServiceName()
             + ", oldDesiredState=" + getDesiredState() + ", newDesiredState="
             + state + ", persisted = " + isPersisted());
       }
@@ -351,6 +370,7 @@ public class ServiceImpl implements Service {
         LOG.debug("Setting DesiredSecurityState of Service" + ", clusterName="
             + cluster.getClusterName() + ", clusterId="
             + cluster.getClusterId() + ", serviceName=" + getName()
+            + ", stackServiceName=" + getStackServiceName()
             + ", oldDesiredSecurityState=" + getSecurityState()
             + ", newDesiredSecurityState=" + securityState);
       }
@@ -384,6 +404,7 @@ public class ServiceImpl implements Service {
         LOG.debug("Setting DesiredStackVersion of Service" + ", clusterName="
             + cluster.getClusterName() + ", clusterId="
             + cluster.getClusterId() + ", serviceName=" + getName()
+            + ", stackServiceName=" + getStackServiceName()
             + ", oldDesiredStackVersion=" + getDesiredStackVersion()
             + ", newDesiredStackVersion=" + stack);
       }
@@ -401,7 +422,7 @@ public class ServiceImpl implements Service {
     readWriteLock.readLock().lock();
     try {
       ServiceResponse r = new ServiceResponse(cluster.getClusterId(),
-          cluster.getClusterName(), getName(),
+          cluster.getClusterName(), getName(), getStackServiceName(), getServiceGroupName(),
           getDesiredStackVersion().getStackId(), getDesiredState().toString());
 
       r.setMaintenanceState(getMaintenanceState().name());
@@ -420,7 +441,7 @@ public class ServiceImpl implements Service {
   public void debugDump(StringBuilder sb) {
     readWriteLock.readLock().lock();
     try {
-      sb.append("Service={ serviceName=" + getName() + ", clusterName="
+      sb.append("Service={ serviceName=" + getName() + "stackServiceName=" + getStackServiceName() + ", clusterName="
           + cluster.getClusterName() + ", clusterId=" + cluster.getClusterId()
           + ", desiredStackVersion=" + getDesiredStackVersion()
           + ", desiredState=" + getDesiredState().toString()
@@ -479,7 +500,7 @@ public class ServiceImpl implements Service {
 
           ServiceInstalledEvent event = new ServiceInstalledEvent(
               getClusterId(), stackId.getStackName(),
-              stackId.getStackVersion(), getName());
+              stackId.getStackVersion(), getName(), getStackServiceName(), getServiceGroupName());
 
           eventPublisher.publish(event);
         } else {
@@ -689,7 +710,7 @@ public class ServiceImpl implements Service {
           StackId stackId = cluster.getDesiredStackVersion();
 
           ServiceRemovedEvent event = new ServiceRemovedEvent(getClusterId(),
-              stackId.getStackName(), stackId.getStackVersion(), getName());
+              stackId.getStackName(), stackId.getStackVersion(), getName(), getStackServiceName(), getServiceGroupName());
 
           eventPublisher.publish(event);
         }


[09/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/mixins/sortable.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/mixins/sortable.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/mixins/sortable.js
new file mode 100644
index 0000000..f766032
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/mixins/sortable.js
@@ -0,0 +1,31 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.SortableMixin.reopen({
+  sort: function (property) {
+    //if same column has been selected, toggle flag, else default it to true
+    if (this.get('sortProperties').objectAt(0) === property) {
+      this.set('sortAscending', !this.get('sortAscending'));
+    } else {
+      this.set('sortAscending', true);
+      this.set('sortProperties', [ property ]);
+    }
+  }
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/database.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/database.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/database.js
new file mode 100644
index 0000000..11ee144
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/database.js
@@ -0,0 +1,25 @@
+/**
+ * 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.
+ */
+
+import DS from 'ember-data';
+
+var Database = DS.Model.extend({
+  name: DS.attr()
+});
+
+export default Database;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/file-resource.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/file-resource.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/file-resource.js
new file mode 100644
index 0000000..47f4911
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/file-resource.js
@@ -0,0 +1,25 @@
+/**
+ * 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.
+ */
+
+import DS from 'ember-data';
+
+export default DS.Model.extend({
+  name: DS.attr(),
+  path: DS.attr(),
+  owner: DS.attr()
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/file.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/file.js
new file mode 100644
index 0000000..c13d4e1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/file.js
@@ -0,0 +1,26 @@
+/**
+ * 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.
+ */
+
+import DS from 'ember-data';
+
+export default DS.Model.extend({
+  fileContent: DS.attr(),
+  hasNext: DS.attr(),
+  page: DS.attr('number'),
+  pageCount: DS.attr()
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/job.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/job.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/job.js
new file mode 100644
index 0000000..9079b5a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/job.js
@@ -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.
+ */
+
+import DS from 'ember-data';
+
+export default DS.Model.extend({
+  title: DS.attr('string'),
+  queryId: DS.attr(),
+  queryFile: DS.attr('string'),
+  owner: DS.attr('string'),
+  dataBase: DS.attr('string'),
+  duration: DS.attr(),
+  status: DS.attr('string'),
+  statusMessage: DS.attr('string'),
+  dateSubmitted: DS.attr('date'),
+  forcedContent: DS.attr('string'),
+  logFile: DS.attr('string'),
+  dagName:  DS.attr('string'),
+  dagId: DS.attr('string'),
+  sessionTag: DS.attr('string'),
+  page: DS.attr(),
+  statusDir: DS.attr('string'),
+  applicationId: DS.attr(),
+  referrer: DS.attr('string'),
+  confFile: DS.attr('string'),
+  globalSettings: DS.attr('string'),
+
+  dateSubmittedTimestamp: function () {
+    var date = this.get('dateSubmitted');
+
+    return date ? date * 1000 : date;
+  }.property('dateSubmitted'),
+
+  uppercaseStatus: function () {
+    var status = this.get('status');
+
+    return status ? status.toUpperCase() : status;
+  }.property('status')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/saved-query.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/saved-query.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/saved-query.js
new file mode 100644
index 0000000..44536af
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/saved-query.js
@@ -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.
+ */
+
+import DS from 'ember-data';
+
+var Model = DS.Model.extend({
+  dataBase: DS.attr('string'),
+  title: DS.attr('string'),
+  queryFile: DS.attr('string'),
+  owner: DS.attr('string'),
+  shortQuery: DS.attr('string')
+});
+
+export default Model;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/udf.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/udf.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/udf.js
new file mode 100644
index 0000000..c64221e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/models/udf.js
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+import DS from 'ember-data';
+import constants from 'hive/utils/constants';
+
+export default DS.Model.extend({
+  name: DS.attr(),
+  classname: DS.attr(),
+  fileResource: DS.belongsTo(constants.namingConventions.fileResource, { async: true }),
+  owner: DS.attr()
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/router.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/router.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/router.js
new file mode 100644
index 0000000..382f1eb
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/router.js
@@ -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.
+ */
+
+import Ember from 'ember';
+import config from './config/environment';
+import constants from 'hive/utils/constants';
+
+var Router = Ember.Router.extend({
+  location: config.locationType
+});
+
+Router.map(function () {
+  var savedQueryPath = constants.namingConventions.routes.queries + '/:' + constants.namingConventions.savedQuery + '_id';
+  var historyQueryPath = constants.namingConventions.routes.history + '/:' + constants.namingConventions.job + '_id';
+
+  this.route(constants.namingConventions.routes.queries);
+  this.route(constants.namingConventions.routes.history);
+  this.route(constants.namingConventions.routes.udfs);
+  this.route(constants.namingConventions.routes.uploadTable);
+
+  this.resource(constants.namingConventions.routes.index, { path: '/' }, function () {
+    this.route(constants.namingConventions.routes.savedQuery, { path: savedQueryPath});
+    this.route(constants.namingConventions.routes.historyQuery, { path: historyQueryPath}, function () {
+      this.route(constants.namingConventions.routes.logs);
+      this.route(constants.namingConventions.routes.results);
+      this.route(constants.namingConventions.routes.explain);
+    });
+  });
+
+  this.route('loading');
+  this.route('splash');
+
+});
+
+export default Router;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/application.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/application.js
new file mode 100644
index 0000000..096ce30
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/application.js
@@ -0,0 +1,89 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+
+  beforeModel: function () {
+    this.transitionTo('splash');
+  },
+
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+
+  setupController: function (controller, model) {
+    var self = this;
+
+    this.store.find(constants.namingConventions.udf).then(function (udfs) {
+      self.controllerFor(constants.namingConventions.udfs).set('udfs', udfs);
+    }, function (error) {
+      self.get('notifyService').error(error);
+    });
+  },
+
+  actions: {
+    openModal: function (modalTemplate, options) {
+      this.controllerFor(modalTemplate).setProperties({
+        content: options.content || {},
+        message: options.message,
+        heading: options.heading,
+        text: options.text,
+        type: options.type || "text",
+        defer: options.defer
+      });
+
+      return this.render(modalTemplate, {
+        into: 'application',
+        outlet: 'modal'
+      });
+    },
+
+    closeModal: function () {
+      return this.disconnectOutlet({
+        outlet: 'modal',
+        parentView: 'application'
+      });
+    },
+
+    openOverlay: function (overlay) {
+      return this.render(overlay.template, {
+        outlet: overlay.outlet,
+        into: overlay.into
+      });
+    },
+
+    closeOverlay: function (overlay) {
+      return this.disconnectOutlet({
+        outlet: overlay.outlet,
+        parentView: overlay.into
+      });
+    },
+
+    removeNotification: function (notification) {
+      this.get('notifyService').removeNotification(notification);
+    },
+
+    willTransition: function(transition) {
+      // close active overlay if we transition
+      this.controllerFor('queryTabs').setDefaultActive();
+
+      return transition;
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/history.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/history.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/history.js
new file mode 100644
index 0000000..848bee8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/history.js
@@ -0,0 +1,46 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+
+  model: function () {
+    var self = this;
+
+    return this.store.find(constants.namingConventions.job).catch(function (error) {
+      self.get('notifyService').error(error);
+    });
+  },
+
+  setupController: function (controller, model) {
+    if (!model) {
+      return;
+    }
+
+    var filteredModel = model.filter(function (job) {
+       //filter out jobs with referrer type of sample, explain and visual explain
+       return (!job.get('referrer') || job.get('referrer') === constants.jobReferrer.job) &&
+              !!job.get('id');
+    });
+
+    controller.set('history', filteredModel);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/explain.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/explain.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/explain.js
new file mode 100644
index 0000000..742f7a8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/explain.js
@@ -0,0 +1,28 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+  setupController: function (controller, model) {
+    this.controllerFor(constants.namingConventions.openQueries).updateTabSubroute(model, constants.namingConventions.subroutes.jobExplain);
+
+    this.controllerFor(constants.namingConventions.routes.index).set('model', model);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/index.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/index.js
new file mode 100644
index 0000000..5959938
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/index.js
@@ -0,0 +1,44 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+import utils from 'hive/utils/functions';
+
+export default Ember.Route.extend({
+  setupController: function (controller, model) {
+    var subroute;
+    var existingTab = this.controllerFor(constants.namingConventions.openQueries).getTabForModel(model);
+
+    if (existingTab) {
+      subroute = existingTab.get('subroute');
+    }
+
+    // filter out hdfs jobs
+    if (utils.isInteger(model.get('id'))) {
+      if (subroute) {
+        this.transitionTo(subroute, model);
+      } else {
+        this.transitionTo(constants.namingConventions.subroutes.jobLogs, model);
+      }
+    } else {
+      this.transitionTo(constants.namingConventions.subroutes.historyQuery, model);
+      this.controllerFor(constants.namingConventions.routes.index).set('model', model);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/logs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/logs.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/logs.js
new file mode 100644
index 0000000..954f725
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/logs.js
@@ -0,0 +1,28 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+  setupController: function (controller, model) {
+    this.controllerFor(constants.namingConventions.openQueries).updateTabSubroute(model, constants.namingConventions.subroutes.jobLogs);
+
+    this.controllerFor(constants.namingConventions.routes.index).set('model', model);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/results.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/results.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/results.js
new file mode 100644
index 0000000..f1593c5
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/history-query/results.js
@@ -0,0 +1,28 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+  setupController: function (controller, model) {
+    this.controllerFor(constants.namingConventions.openQueries).updateTabSubroute(model, constants.namingConventions.subroutes.jobResults);
+
+    this.controllerFor(constants.namingConventions.routes.index).set('model', model);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/index.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/index.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/index.js
new file mode 100644
index 0000000..120a102
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/index.js
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+  beforeModel: function () {
+    var model = this.controllerFor(constants.namingConventions.routes.index).get('model');
+
+    if (model && !model.get('isDeleted')) {
+      if (model.get('constructor.typeKey') === constants.namingConventions.job) {
+        this.transitionTo(constants.namingConventions.subroutes.historyQuery, model);
+      } else {
+        this.transitionTo(constants.namingConventions.subroutes.savedQuery, model);
+      }
+    } else {
+      this.controllerFor(constants.namingConventions.openQueries).navigateToLastTab();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/saved-query.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/saved-query.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/saved-query.js
new file mode 100644
index 0000000..0366b0d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/index/saved-query.js
@@ -0,0 +1,43 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+  setupController: function (controller, model) {
+    // settings modify fileContent to extract the settings
+    // when you load a saved query use the original fileContent
+    // this.store.find('file', model.get('queryFile'))
+    //   .then(function(queryFile) {
+    //     var changes = queryFile.changedAttributes();
+    //     if (changes.fileContent && changes.fileContent[0]) {
+    //       queryFile.set('fileContent', changes.fileContent[0]);
+    //     }
+    //   });
+
+    this.controllerFor(constants.namingConventions.routes.index).set('model', model);
+  },
+
+  actions: {
+    error: function () {
+      this.store.unloadAll(constants.namingConventions.savedQuery);
+      this.transitionTo(constants.namingConventions.routes.index);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/loading.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/loading.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/loading.js
new file mode 100644
index 0000000..8719170
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/loading.js
@@ -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
+ *
+ *     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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/queries.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/queries.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/queries.js
new file mode 100644
index 0000000..29e144b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/queries.js
@@ -0,0 +1,40 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+
+  model: function () {
+    var self = this;
+
+    return this.store.find(constants.namingConventions.savedQuery).catch(function (error) {
+      self.get('notifyService').error(error);
+    });
+  },
+
+  setupController: function (controller, model) {
+    if (!model) {
+      return;
+    }
+
+    controller.set('queries', model);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/splash.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/splash.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/splash.js
new file mode 100644
index 0000000..05bcbcf
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/splash.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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+
+  model: function() {
+    return Ember.Object.create({
+      hdfsTest: null,
+      hdfsTestDone: null,
+      hiveserverTest: null,
+      hiveserverTestDone: null,
+      atsTest: null,
+      atsTestDone: null,
+      percent: 0
+    });
+  },
+
+  setupController: function(controller, model) {
+
+    if (!model) {
+      return;
+    }
+
+    controller.set('model', model);
+    var self = this;
+    controller.startTests().then(function() {
+
+    if (model.get("hiveserverTest") && model.get("hdfsTest") && model.get("atsTest")) {
+      Ember.run.later(this, function() {
+        self.send('transition');
+      }, 2000);
+    }
+    });
+  },
+
+  actions: {
+    transition: function() {
+      this.transitionTo('index');
+    }
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/udfs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/udfs.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/udfs.js
new file mode 100644
index 0000000..5a96cd6
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/udfs.js
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Route.extend({
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+
+  setupController: function (controller, model) {
+    this._super();
+
+    var self = this;
+
+    this.store.find(constants.namingConventions.fileResource).then(function (fileResources) {
+      controller.set('fileResources', fileResources);
+    }).catch(function (error) {
+      self.get('notifyService').error(error);
+    });;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/serializers/database.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/serializers/database.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/serializers/database.js
new file mode 100644
index 0000000..f598b20
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/serializers/database.js
@@ -0,0 +1,41 @@
+/**
+ * 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.
+ */
+
+import DS from 'ember-data';
+
+export default DS.JSONSerializer.extend({
+  extractArray: function (store, primaryType, rawPayload) {
+    var databases = rawPayload.databases.map(function (database) {
+      return {
+        id: database,
+        name: database
+      };
+    });
+
+    var payload = { databases: databases };
+    return this._super(store, primaryType, payload);
+  },
+
+  normalizePayload: function (payload) {
+    var normalized = payload.databases.map(function (database) {
+      return database;
+    });
+
+    return this._super(normalized);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/serializers/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/serializers/file.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/serializers/file.js
new file mode 100644
index 0000000..416db0c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/serializers/file.js
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+
+import DS from 'ember-data';
+
+export default DS.RESTSerializer.extend({
+  primaryKey: 'filePath'
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/database.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/database.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/database.js
new file mode 100644
index 0000000..2a6f5d4
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/database.js
@@ -0,0 +1,243 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Service.extend({
+  store: Ember.inject.service(),
+
+  pageCount: 10,
+  selectedDatabase: null,
+  selectedTables: null,
+  databases: [],
+
+  init: function () {
+    this._super();
+
+    var databaseAdapter = this.container.lookup('adapter:database');
+    var baseUrl = databaseAdapter.buildURL() + '/' +
+                  databaseAdapter.pathForType(constants.namingConventions.database) + '/';
+
+    this.set('baseUrl', baseUrl);
+  },
+
+  getDatabases: function () {
+    var defer = Ember.RSVP.defer();
+    var self = this;
+
+    this.get('store').unloadAll(constants.namingConventions.database);
+    this.get('store').fetchAll(constants.namingConventions.database).then(function (databases) {
+      self.set('databases', databases);
+      defer.resolve(databases);
+    }, function (error) {
+      defer.reject(error);
+    })
+
+    return defer.promise;
+  },
+
+  // This will do a ajax call to fetch the current database by by-passing the store.
+  // As we want to retain the current state of databases in store and just want to
+  // find the current databases in the server
+  getDatabasesFromServer: function() {
+    var defer = Ember.RSVP.defer();
+    var url = this.get('baseUrl');
+    Ember.$.getJSON(url).then(function(data) {
+      defer.resolve(data.databases);
+    }, function(err) {
+      defer.reject(err);
+    });
+    return defer.promise;
+  },
+
+  setDatabaseByName: function (name) {
+    var database = this.databases.findBy('name', name);
+
+    if (database) {
+      this.set('selectedDatabase', database);
+    }
+  },
+
+  getColumnsPage: function (databaseName, table, searchTerm, firstSearchPage) {
+    var defer = Ember.RSVP.defer();
+
+    var url = this.get('baseUrl') +
+              databaseName +
+              '/table/' +
+              table.get('name');
+
+    url += '.page?searchId&count=' + this.get('pageCount');
+    url += '&columns=3,5,6,8';
+
+    if (searchTerm) {
+      url += '&searchId=searchColumns' + '&like=' + searchTerm;
+
+      if (firstSearchPage) {
+        url += '&first=true';
+      }
+    } else if (!table.get('columns.length')) {
+      url += '&first=true';
+    }
+
+    Ember.$.getJSON(url).then(function (data) {
+      Ember.run(function () {
+        var columns;
+
+        columns = data.rows.map(function (row) {
+            return Ember.Object.create({
+              name: row[0],
+              type: row[1],
+              precision : row[2],
+              scale : row[3]
+            });
+        });
+
+        defer.resolve({
+          columns: columns,
+          hasNext: data.hasNext
+        });
+      });
+    }, function (err) {
+      defer.reject(err);
+    });
+
+    return defer.promise;
+  },
+
+  getTablesPage: function (database, searchTerm, firstSearchPage) {
+    var defer = Ember.RSVP.defer(),
+        url = this.get('baseUrl') +
+              database.get('name') +
+              '/table.page?count=';
+
+    url += this.get('pageCount');
+
+    if (searchTerm) {
+      url += '&searchId=searchTables' + '&like=' + searchTerm;
+
+      if (firstSearchPage) {
+        url += '&first=true';
+      }
+    } else if (!database.get('tables.length')) {
+      url += '&first=true';
+    }
+
+    Ember.$.getJSON(url).then(function (data) {
+      var tables;
+
+      tables = data.rows.map(function (row) {
+        return Ember.Object.create({
+          name: row[0]
+        });
+      });
+
+      defer.resolve({
+        tables: tables,
+        hasNext: data.hasNext
+      });
+    }, function (err) {
+      defer.reject(err);
+    });
+
+    return defer.promise;
+  },
+
+  getAllTables: function (db) {
+    var defer = Ember.RSVP.defer();
+    var database = db || this.get('selectedDatabase');
+    var self;
+    var url;
+
+    if (!database) {
+      defer.resolve();
+    } else if (database.tables && !database.get('hasNext')) {
+      this.set('selectedTables', database.tables.mapProperty('name'));
+      defer.resolve();
+    } else {
+      self = this;
+      url = this.get('baseUrl') + database.get('name') + '/table';
+
+      Ember.$.getJSON(url).then(function (data) {
+        var tables = data.tables.map(function (table) {
+          return Ember.Object.create({
+            name: table
+          });
+        });
+
+        //don't use Ember.Object.set since it can be very expensive for large collections (e.g. 15000 tables),
+        //thus we should not do any bindings directly on the 'tables' collection.
+        database.tables = tables;
+
+        Ember.run(function () {
+          self.set('selectedTables', tables.mapProperty('name'));
+        });
+
+        defer.resolve();
+      }, function (err) {
+        defer.reject(err);
+      });
+    }
+
+    return defer.promise;
+  },
+
+  getAllColumns: function (tableName, db) {
+    var database = db || this.get('selectedDatabase');
+    var defer = Ember.RSVP.defer();
+    var table;
+    var self;
+    var url;
+
+    if (!database) {
+      defer.resolve();
+    } else {
+      table = database.tables.findBy('name', tableName);
+
+      if (!table) {
+        defer.resolve();
+      } else if (table.columns && !table.get('hasNext')) {
+        this.get('selectedTables')[tableName] = table.columns.mapProperty('name');
+        defer.resolve();
+      } else {
+        self = this;
+        url = this.get('baseUrl') + database.get('name') + '/table/' + tableName
+
+        Ember.$.getJSON(url).then(function (data) {
+          var columns = data.columns.map(function (column) {
+            return Ember.Object.create({
+              name: column[0],
+              type: column[1]
+            });
+          });
+
+          table.columns = columns;
+          table.set('hasNext', false);
+
+          self.get('selectedTables')[tableName] = columns.mapProperty('name');
+
+          defer.resolve();
+        }, function (err) {
+          defer.reject(err);
+        });
+      }
+    }
+
+    return defer.promise;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/file.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/file.js
new file mode 100644
index 0000000..7f01795
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/file.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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Service.extend({
+  files: [],
+  store: Ember.inject.service(),
+
+  loadFile: function (path) {
+    var self = this;
+    var defer = Ember.RSVP.defer();
+    var file = this.files.findBy('id', path);
+
+    if (file) {
+      defer.resolve(file);
+    } else {
+      this.get('store').find(constants.namingConventions.file, path).then(function (file) {
+        defer.resolve(self.files.pushObject(file));
+      }, function (err) {
+        defer.reject(err);
+      });
+    }
+
+    return defer.promise;
+  },
+
+  reloadFile: function (path) {
+    var defer = Ember.RSVP.defer();
+
+    this.get('store').find(constants.namingConventions.file, path).then(function (file) {
+      file.reload().then(function (reloadedFile) {
+        defer.resolve(reloadedFile);
+      }, function (err) {
+        defer.reject(err);
+      });
+    }, function (err) {
+      defer.reject(err);
+    });
+
+    return defer.promise;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/job-progress.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/job-progress.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/job-progress.js
new file mode 100644
index 0000000..1e0b96b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/job-progress.js
@@ -0,0 +1,102 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Service.extend({
+  jobs: [],
+
+  setupProgress: function (currentModel) {
+    var job = this.jobs.findBy('model', currentModel);
+
+    if (!job) {
+      job = this.jobs.pushObject(Ember.Object.create({
+        model: currentModel,
+        stages: [],
+        totalProgress: 0,
+        retrievingProgress: false,
+      }));
+    }
+
+    this.set('currentJob', job);
+  },
+
+  updateProgress: function () {
+    var job = this.get('currentJob');
+
+    if (!job.get('model.dagId')) {
+      return;
+    }
+
+    if (job.get('totalProgress') < 100 && !job.get('retrievingProgress')) {
+      this.reloadProgress(job);
+    }
+  }.observes('currentJob.model.dagId'),
+
+  reloadProgress: function (job) {
+    var self = this;
+    var url = '%@/%@/%@/progress'.fmt(this.container.lookup('adapter:application').buildURL(),
+                                         constants.namingConventions.jobs,
+                                         job.get('model.id'));
+
+    job.set('retrievingProgress', true);
+
+    Ember.$.getJSON(url).then(function (data) {
+      var total = 0;
+      var length = Object.keys(data.vertexProgresses).length;
+
+      if (!job.get('stages.length')) {
+        data.vertexProgresses.forEach(function (vertexProgress) {
+          var progress = vertexProgress.progress * 100;
+
+          job.get('stages').pushObject(Ember.Object.create({
+            name: vertexProgress.name,
+            value: progress
+          }));
+
+          total += progress;
+        });
+      } else {
+        data.vertexProgresses.forEach(function (vertexProgress) {
+          var progress = vertexProgress.progress * 100;
+
+          job.get('stages').findBy('name', vertexProgress.name).set('value', progress);
+
+          total += progress;
+        });
+      }
+
+      total /= length;
+
+      job.set('totalProgress', total);
+
+      if (job.get('model.isRunning') && total < 100) {
+        Ember.run.later(function () {
+          self.reloadProgress(job);
+        }, 1000);
+      } else {
+        job.set('retrievingProgress');
+      }
+    });
+  },
+
+  isJob: function (model) {
+    return model.get('constructor.typeKey') === constants.namingConventions.job;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/job.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/job.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/job.js
new file mode 100644
index 0000000..6cb4170
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/job.js
@@ -0,0 +1,56 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Service.extend({
+  stopJob: function (job) {
+    var self = this;
+    var id = job.get('id');
+    var url = this.container.lookup('adapter:application').buildURL();
+    url +=  "/jobs/" + id;
+
+    job.set('isCancelling', true);
+
+    Ember.$.ajax({
+       url: url,
+       type: 'DELETE',
+       headers: {
+        'X-Requested-By': 'ambari',
+       },
+       success: function () {
+         job.reload();
+       }
+    });
+  },
+
+  fetchJobStatus: function (jobId) {
+    console.log("finding status of job : ", jobId);
+    var self = this;
+    var url = this.container.lookup('adapter:application').buildURL();
+    url +=  "/jobs/" + jobId + "/status";
+
+    return Ember.$.ajax({
+      url: url,
+      type: 'GET',
+      headers: {
+        'X-Requested-By': 'ambari'
+      }
+    });
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/notify.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/notify.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/notify.js
new file mode 100644
index 0000000..04c13ff
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/notify.js
@@ -0,0 +1,113 @@
+/**
+* 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.
+*/
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Service.extend({
+  types: constants.notify,
+
+  messages       : Ember.ArrayProxy.create({ content : [] }),
+  notifications  : Ember.ArrayProxy.create({ content : [] }),
+  unseenMessages : Ember.ArrayProxy.create({ content : [] }),
+
+  add: function (type, message, body) {
+    var formattedBody = this.formatMessageBody(body);
+
+    var notification = Ember.Object.create({
+      type    : type,
+      message : message,
+      body    : formattedBody
+    });
+
+    this.messages.pushObject(notification);
+    this.notifications.pushObject(notification);
+    this.unseenMessages.pushObject(notification);
+  },
+
+  info: function (message, body) {
+    this.add(this.types.INFO, message, body);
+  },
+
+  warn: function (message, body) {
+    this.add(this.types.WARN, message, body);
+  },
+
+  pushError: function (message, body) {
+    this.add(this.types.ERROR, message, body);
+  },
+
+  error: function (error) {
+    var message,
+        body;
+
+    if (error.responseJSON) {
+      message = error.responseJSON.message;
+      body = error.responseJSON.trace;
+    } else if (error.errorThrown) {
+      message = error.errorThrown;
+    } else if (error.message) {
+      message = error.message;
+    } else {
+      message = error;
+    }
+
+    this.add(this.types.ERROR, message, body);
+  },
+
+  success: function (message, body) {
+    this.add(this.types.SUCCESS, message, body);
+  },
+
+  formatMessageBody: function (body) {
+    if (!body) {
+      return;
+    }
+
+    if (typeof body === "string") {
+      return body;
+    }
+
+    if (typeof body === "object") {
+      var formattedBody = "";
+      for (var key in body) {
+        formattedBody += "\n\n%@:\n%@".fmt(key, body[key]);
+      }
+
+      return formattedBody;
+    }
+  },
+
+  removeMessage: function (message) {
+    this.messages.removeObject(message);
+    this.notifications.removeObject(message);
+  },
+
+  removeNotification: function (notification) {
+    this.notifications.removeObject(notification);
+  },
+
+  removeAllMessages: function () {
+    this.messages.clear();
+  },
+
+  markMessagesAsSeen: function () {
+    if (this.unseenMessages.get('length')) {
+      this.unseenMessages.removeAt(0, this.unseenMessages.get('length'));
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/session.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/session.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/session.js
new file mode 100644
index 0000000..d7d448d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/session.js
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Service.extend({
+
+  updateSessionStatus: function (model) {
+    var sessionActive = model.get('sessionActive');
+    var sessionTag    = model.get('sessionTag');
+    var adapter       = this.container.lookup('adapter:application');
+    var url           = adapter.buildURL() + '/jobs/sessions/' + sessionTag;
+
+    if (sessionTag && sessionActive === undefined) {
+      adapter.ajax(url, 'GET')
+        .then(function (response) {
+          model.set('sessionActive', response.session.actual);
+        })
+        .catch(function () {
+          model.set('sessionActive', false);
+        });
+    }
+  },
+
+  killSession: function (model) {
+    var sessionTag = model.get('sessionTag');
+    var adapter    = this.container.lookup('adapter:application');
+    var url        = adapter.buildURL() + '/jobs/sessions/' + sessionTag;
+
+    return adapter.ajax(url, 'DELETE');
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/settings.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/settings.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/settings.js
new file mode 100644
index 0000000..b813bbf
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/settings.js
@@ -0,0 +1,175 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Service.extend({
+
+  notifyService: Ember.inject.service('notify'),
+
+  settings: Ember.ArrayProxy.create({ content: [] }),
+  predefinedSettings: constants.hiveParameters,
+
+  _createSetting: function(name, value) {
+    var setting = Ember.Object.createWithMixins({
+      valid     : true,
+      value     : Ember.computed.alias('selection.value'),
+      selection : Ember.Object.create()
+    });
+
+    if (name) {
+      setting.set('key', Ember.Object.create({ name: name }));
+    }
+
+    if (value) {
+      setting.set('selection.value', value);
+    }
+
+    return setting;
+  },
+
+  _createDefaultSettings: function(settings) {
+    if (!settings) {
+      return;
+    }
+
+    for (var key in settings) {
+      this.get('settings').pushObject(this._createSetting(key, settings[key]));
+    }
+  },
+
+  _validate: function () {
+    var settings = this.get('settings');
+    var predefinedSettings = this.get('predefinedSettings');
+
+    settings.forEach(function (setting) {
+      var predefined = predefinedSettings.findBy('name', setting.get('key.name'));
+
+      if (!predefined) {
+        return;
+      }
+
+      if (predefined.values && predefined.values.contains(setting.get('value'))) {
+        setting.set('valid', true);
+        return;
+      }
+
+      if (predefined.validate && predefined.validate.test(setting.get('value'))) {
+        setting.set('valid', true);
+        return;
+      }
+
+      if (!predefined.validate) {
+        setting.set('valid', true);
+        return;
+      }
+
+      setting.set('valid', false);
+    });
+  }.observes('settings.@each.value', 'settings.@each.key'),
+
+  add: function() {
+    this.get('settings').pushObject(this._createSetting());
+  },
+
+  createKey: function(name) {
+    var key = { name: name };
+    this.get('predefinedSettings').pushObject(key);
+
+    this.get('settings').findBy('key', null).set('key', key);
+  },
+
+  remove: function(setting) {
+    this.get('settings').removeObject(setting);
+  },
+
+  removeAll: function() {
+    this.get('settings').clear();
+  },
+
+  loadDefaultSettings: function() {
+    var adapter       = this.container.lookup('adapter:application');
+    var url           = adapter.buildURL() + '/savedQueries/defaultSettings';
+    var self = this;
+
+    adapter.ajax(url)
+      .then(function(response) {
+        self._createDefaultSettings(response.settings);
+      })
+      .catch(function(error) {
+        self.get('notifyService').error(error);
+      });
+  },
+
+  saveDefaultSettings: function() {
+    var self     = this;
+    var data     = {};
+    var adapter  = this.container.lookup('adapter:application');
+    var url      = adapter.buildURL() + '/savedQueries/defaultSettings';
+    var settings = this.get('settings');
+
+    settings.forEach(function(setting) {
+      data[ setting.get('key.name') ] = setting.get('value');
+    });
+
+    adapter.ajax(url, 'POST', {
+      data: {settings: data }
+    })
+    .then(function(response) {
+      if (response && response.settings) {
+        self.get('notifyService').success(Ember.I18n.t('alerts.success.settings.saved'));
+      } else {
+        self.get('notifyService').error(response);
+      }
+    });
+  },
+
+  getSettings: function() {
+    var settings = this.get('settings');
+    var asString = "";
+
+    if (!settings.get('length')) {
+      return asString;
+    }
+
+    settings.forEach(function(setting) {
+      asString += "set %@=%@;\n".fmt(setting.get('key.name'), setting.get('value'));
+    });
+
+    asString += constants.globalSettings.comment;
+
+    return asString;
+  },
+
+  parseGlobalSettings: function(query, model) {
+    if (!query || !model || !model.get('globalSettings')) {
+      return;
+    }
+
+    var globals = model.get('globalSettings');
+    var content = query.get('fileContent');
+
+    if (globals !== this.getSettings()) {
+      return;
+    }
+
+    query.set('fileContent', content.replace(globals, ''));
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/app.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/app.scss b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/app.scss
new file mode 100644
index 0000000..8f60595
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/app.scss
@@ -0,0 +1,680 @@
+/**
+ * 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.
+ */
+
+@import 'vars';
+@import 'dropdown-submenu';
+@import 'mixins';
+@import 'notifications';
+@import 'query-tabs';
+
+a {
+  word-wrap: break-word;
+}
+
+@keyframes flash {
+  0% {
+    background-color: transparent;
+  }
+
+  25% {
+    background-color: #428bca;
+    color: #fff;
+  }
+
+  50% {
+    background-color: transparent;
+    color: #333;
+  }
+
+  75% {
+    background-color: #428bca;
+    color: #fff;
+  }
+
+  100% {
+    background-color: transparent;
+    color: #333;
+  }
+}
+
+.flash {
+  animation: flash 1s;
+}
+
+@-webkit-keyframes fadeIn {
+  0% {opacity: 0;}
+  100% {opacity: 1;}
+}
+
+@keyframes fadeIn {
+  0% {opacity: 0;}
+  100% {opacity: 1;}
+}
+
+.fadeIn {
+  -webkit-animation-name: fadeIn;
+          animation-name: fadeIn;
+}
+
+@-webkit-keyframes fadeOut {
+  0% {opacity: 1;}
+  100% {opacity: 0;}
+}
+
+@keyframes fadeOut {
+  0% {opacity: 1;}
+  100% {opacity: 0;}
+}
+
+.fadeOut {
+  -webkit-animation-name: fadeOut;
+          animation-name: fadeOut;
+}
+
+.empty-list {
+  text-align: center;
+}
+
+#content {
+  padding: 20px 0;
+}
+
+#index-content {
+  display: flex;
+}
+
+#visual-explain {
+  white-space: nowrap;
+
+  .panel-body {
+    overflow: hidden;
+  }
+}
+
+.index-overlay {
+  position: absolute;
+  left: 0;
+  width: 0;
+  z-index: 99;
+  background: white;
+}
+
+aside  {
+  hr {
+    margin: 10px 0;
+  }
+
+  &.no-width {
+    width: 0;
+    overflow: hidden;
+
+    @include animate-width(0.25s);
+  }
+
+  &.col-md-3 {
+    @include animate-width(0.25s);
+  }
+}
+
+.halfed {
+  width: 50%;
+}
+
+.no-padding {
+  padding: 0;
+}
+
+.no-margin {
+  margin: 0;
+}
+
+.toolbox {
+  margin: 15px 15px 0 0;
+
+  .insert-udfs {
+    display: inline-block;
+  }
+}
+
+.history-date-range {
+  white-space: nowrap;
+}
+.history-date-range .fromDate,
+.history-date-range .toDate {
+  width: 48%;
+}
+
+.form-control::-moz-placeholder {
+  color: $placeholder-color;
+}
+
+.form-control:-ms-input-placeholder {
+  color: $placeholder-color;
+}
+
+.form-control::-webkit-input-placeholder {
+  color: $placeholder-color;
+}
+
+.form-group {
+  margin-bottom: 0;
+}
+
+.secondary-row {
+  background: $panel-background;
+}
+
+.btn-group {
+  .dropdown-menu {
+    right: 0;
+    left: auto;
+  }
+}
+
+.CodeMirror {
+  border: 0 1px solid $border-color;
+}
+
+.grip {
+  height: 20px;
+  border: 0 1px 1px solid $border-color;
+  background-color: $panel-background;
+  color: #bbb;
+  text-align: center;
+  font-size: inherit;
+}
+
+.slider {
+  min-width: 200px;
+  margin-right: 8px;
+}
+
+.slider-labels {
+  font-size: 10px;
+}
+
+.modal-backdrop {
+  background-color: white;
+}
+
+.gray {
+  background-color: gray;
+}
+
+.green {
+  background-color: #99CC00;
+}
+
+.red {
+  background-color: #ff3300;
+}
+
+.orange {
+  background-color: #FF9933;
+}
+
+.yellow {
+  background-color: #CCCC00;
+}
+
+.blue {
+  background-color: blue;
+}
+
+.UNKNOWN {
+  color: gray;
+}
+
+.RUNNING, .PENDING, .INITIALIZED, .fa-edit {
+  color: orange;
+}
+
+.SUCCEEDED {
+  color: green;
+}
+
+.CANCELED, .ERROR, .FAILED, .KILLED {
+  color: red;
+}
+
+dropdown .fa-remove {
+  color: red;
+}
+
+.CLOSED {
+  color: blue;
+}
+
+.query-container {
+  position: relative;
+  padding-right: 0;
+  -moz-box-sizing: border-box;
+
+  &.col-md-9 {
+    @include animate-width(0.25s);
+  }
+
+  &.col-md-12 {
+    @include animate-width(0.25s);
+  }
+}
+
+.main-content {
+  width: 96%;
+}
+
+.queries-icon {
+  font-size: 20px;
+
+  &.active {
+    color: white;
+  }
+
+  &.text-icon {
+    font-size: 12px;
+    font-weight: 800;
+  }
+}
+
+.query-context-tab {
+  background: #f1f1f1;
+  border-left: 2px solid #428bca;
+
+  &.active {
+    color: #428bca;
+    border-left: 2px solid white;
+  }
+}
+
+.alert {
+  margin-bottom: 5px;
+  padding-bottom: 10px;
+  padding-top: 10px;
+
+  strong {
+    text-decoration: underline;
+  }
+
+  .alert-message {
+    max-height: 250px;
+    overflow-y: auto;
+  }
+}
+
+body {
+  a, i {
+    cursor: pointer;  }
+
+  dropdown {
+    .btn-group, .dropdown-toggle, .dropdown-menu {
+      width: 100%;
+    }
+  }
+
+  tabs {
+    ul li{
+      background: $panel-background;
+    }
+  }
+
+  table {
+    tbody tr {
+      border: 1px solid #ccc;
+    }
+
+    td *{
+      white-space: nowrap;
+    }
+  }
+
+  column-filter {
+    display: -webkit-inline-flex; /* Safari */
+    display: inline-flex;
+
+    .slider {
+      margin-top: 10px;
+    }
+
+    .btn {
+      padding: 0;
+      border: 0;
+    }
+
+    .form-control {
+      width: auto;
+    }
+
+    .fa {
+      padding: 10px 0;
+    }
+  }
+}
+
+.CodeMirror-hints {
+  min-width: 200px;
+  z-index: 100;
+}
+
+.spinner {
+  width: 36px;
+  height: 36px;
+  background: url("/img/spinner.gif");
+  background-repeat: no-repeat;
+  margin: 0 auto;
+
+  &.small {
+    background-size: 20px;
+    width: 20px;
+    height: 20px;
+  }
+
+  &.inline-spinner {
+    vertical-align: middle;
+    display: inline-block;
+  }
+}
+
+.ellipsis{
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  overflow: hidden;
+  display:inline-block;
+}
+
+.databases {
+  max-height: 500px;
+  overflow-y: auto;
+
+  .tables {
+    padding-left: 10px;
+
+    .columns {
+      padding-left: 10px;
+      .column-name{
+        width: 10em;
+        font-weight: bold;
+        @extend .ellipsis;
+      }
+    }
+  }
+}
+
+@media only screen and (max-width : 992px) {
+  .databases {
+    .tables {
+      .columns {
+        .column-name{
+          width: 5em;
+        }
+      }
+    }
+  }
+}
+
+.collapsible-row {
+  width: 13em;
+  @extend .ellipsis;
+}
+
+.selectize-control.plugin-remove_button [data-value] {
+  padding-right: 0 !important;
+}
+
+.query-editor-panel .panel-body {
+  position: relative;
+  padding-right: 0;
+}
+
+.settings-containers-toggle {
+  position: absolute;
+  top: 0;
+  right: 25px;
+  cursor: pointer;
+}
+
+.settings-container .close-settings {
+  float: right;
+  font-size: 18px;
+  cursor: pointer;
+  line-height: 24px;
+}
+
+.settings-controls {
+  margin: 10px 0;
+}
+
+.setting {
+  float: left;
+  padding: 10px 0 0 0;
+
+  .input-group {
+    width: 100%;
+  }
+  .input-group-addon {
+    text-align: justify;
+    width: 50%;
+  }
+}
+
+.setting .remove {
+  line-height: 30px;
+  font-size: 18px;
+  cursor: pointer;
+}
+
+.setting .setting-input-value {
+  width: calc(100% - 30px);
+  display: inline-block;
+}
+.setting .global-setting-value {
+  width: calc(100% - 25px);
+}
+
+.settings-set .settings-set-selector {
+  display: inline-block;
+  width: 300px;
+}
+
+tree-view ul li {
+  padding-left: 10px;
+}
+
+#tez-ui iframe {
+  width: 100%;
+  height: 822px;
+  border: none;
+}
+
+.edge {
+  text-align: center;
+  font-size: 10px;
+  font-weight: 800;
+
+  .edge-path {
+    margin-top: -55px;
+    height: 2px;
+    background-color: #dedede;
+    position: absolute;
+  }
+
+  .edge-arrow {
+    position: absolute;
+    width: 0;
+    height: 0;
+    border-top: 5px solid transparent;
+    border-bottom: 5px solid transparent;
+    border-right: 10px solid black;
+  }
+}
+
+.nodes {
+  width: 100%;
+  position: relative;
+
+  .node-container {
+    text-align: center;
+
+    .node {
+      border: 1px solid #bbb;
+      background: #fefefe;
+      font-size: 12px;
+      box-sizing: border-box;
+      text-align: left;
+      max-width: 200px;
+      margin: 0 25px 100px 0;
+      display: inline-block;
+      vertical-align: top;
+
+      @include box-shadow(1px, 1px, 15px, #888888);
+
+      &.table-node, &.output-node {
+        background-color: ghostwhite;
+        color: gray;
+        padding: 5px;
+        text-align: center;
+        min-width: 100px;
+        line-height: 8px;
+        vertical-align: bottom;
+        margin-bottom: 50px;
+      }
+
+      .node-heading {
+        padding: 5px;
+        text-align: center;
+        background-color: lightslategrey;
+        color: white;
+      }
+
+      .node-content {
+        max-height: 300px;
+        white-space: normal;
+        padding: 5px;
+        overflow-y: auto;
+        overflow-x: hidden;
+
+        .fa {
+          color: green;
+        }
+      }
+
+      .progress {
+        border-radius: 0;
+        margin: 0 10px 10px 10px;
+      }
+    }
+  }
+}
+
+.progress-bar {
+  min-width: 2em;
+}
+
+.messages-controls {
+  margin: 0 0 10px;
+}
+
+#query-results, #upload-table{
+  .table {
+    display: inline-block;
+    overflow: auto;
+  }
+
+  .query-results-tools {
+    margin-top: 10px;
+  }
+
+  input, .selectize-input {
+    width: 300px;
+  }
+}
+
+#upload-controls {
+  .table {
+    display: inline-block;
+    overflow: auto;
+  }
+
+  input, .selectize-input {
+    width: 94px;
+    font-size : smaller;
+  }
+
+  .hidden {
+    visibility:hidden;
+  }
+
+  .visible {
+    visibility:visible;
+  }
+
+  td {
+    padding-right : 5px;
+  }
+}
+
+
+.data-upload-form tr td {
+    padding-right : 5px;
+}
+
+td.data-upload-form-label {
+    width: 150px;
+    padding-left: 50px;
+}
+td.data-upload-form-field {
+    width: 350px;
+}
+
+#hdfs-param input {
+  width: 80%;
+  display: inline;
+}
+
+#visualization{
+    .max-rows {
+      float: right;
+    }
+}
+
+#visualization{
+    .max-rows {
+      float: right;
+    }
+}
+
+.mozBoxSizeFix {
+  -moz-box-sizing: border-box;
+}
+.show-data {
+    display : block;
+}
+.hide-data {
+    display : none;
+}
+.no-shadow {
+  box-shadow: none;
+  width: inherit;
+}
+
+.widget-controls {
+  padding-right: 10px;
+}
+
+table.no-border, table.no-border tr, table.no-border tr td {
+  border: none;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/dropdown-submenu.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/dropdown-submenu.scss b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/dropdown-submenu.scss
new file mode 100644
index 0000000..bab2216
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/dropdown-submenu.scss
@@ -0,0 +1,65 @@
+/**
+ * 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.
+ */
+
+.dropdown-submenu {
+    position:relative;
+}
+
+.dropdown-submenu>.dropdown-menu {
+    top:0;
+    left:100%;
+    margin-top:-6px;
+    margin-left:-1px;
+    -webkit-border-radius:0 6px 6px 6px;
+    -moz-border-radius:0 6px 6px 6px;
+    border-radius:0 6px 6px 6px;
+}
+
+.dropdown-submenu:hover>.dropdown-menu {
+    display:block;
+}
+
+.dropdown-submenu>a:after {
+    display:block;
+    content:" ";
+    float:right;
+    width:0;
+    height:0;
+    border-color:transparent;
+    border-style:solid;
+    border-width:5px 0 5px 5px;
+    border-left-color:#cccccc;
+    margin-top:5px;
+    margin-right:-10px;
+}
+
+.dropdown-submenu:hover>a:after {
+    border-left-color:#ffffff;
+}
+
+.dropdown-submenu.pull-left {
+    float:none;
+}
+
+.dropdown-submenu.pull-left>.dropdown-menu {
+    left:-100%;
+    margin-left:10px;
+    -webkit-border-radius:6px 0 6px 6px;
+    -moz-border-radius:6px 0 6px 6px;
+    border-radius:6px 0 6px 6px;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/mixins.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/mixins.scss b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/mixins.scss
new file mode 100644
index 0000000..acaa386
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/mixins.scss
@@ -0,0 +1,28 @@
+/**
+* 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.
+*/
+
+@mixin box-shadow($horizontal, $vertical, $blur, $color) {
+  -webkit-box-shadow: $horizontal $vertical $blur $color;
+     -moz-box-shadow: $horizontal $vertical $blur $color;
+          box-shadow: $horizontal $vertical $blur $color;
+}
+
+@mixin animate-width($time) {
+  -webkit-transition: $time;
+  transition: width $time;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/notifications.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/notifications.scss b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/notifications.scss
new file mode 100644
index 0000000..166056b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/notifications.scss
@@ -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.
+*/
+
+.notifications-container {
+  position: absolute;
+  top: 4px;
+  right: 20px;
+  width: 600px;
+  z-index: 9999;
+}
+
+.notification > .fa {
+  width: 15px;
+  text-align: center;
+  margin-right: 10px;
+}
+
+.notifications-container .notification {
+  word-wrap: break-word;
+  max-height: 200px;
+  overflow-x: auto;
+}


[33/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/rest/BootStrapResource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/rest/BootStrapResource.java b/ambari-server/src/main/java/org/apache/ambari/server/api/rest/BootStrapResource.java
index 5672598..f2f0a95 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/rest/BootStrapResource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/rest/BootStrapResource.java
@@ -45,7 +45,6 @@ import org.apache.commons.logging.LogFactory;
 
 import com.google.inject.Inject;
 
-@Path("/bootstrap")
 public class BootStrapResource {
 
   private static BootStrapImpl bsImpl;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/rest/HealthCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/rest/HealthCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/api/rest/HealthCheck.java
index 2f31611..802f7eb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/rest/HealthCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/rest/HealthCheck.java
@@ -28,7 +28,6 @@ import javax.ws.rs.core.MediaType;
  * or not
  */
 
-@Path("/check")
 public class HealthCheck {
   private static final String status = "RUNNING";
   // This method is called if TEXT_PLAIN is request

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/rest/KdcServerReachabilityCheck.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/rest/KdcServerReachabilityCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/api/rest/KdcServerReachabilityCheck.java
index 898e7e6..bb08a0a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/rest/KdcServerReachabilityCheck.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/rest/KdcServerReachabilityCheck.java
@@ -36,7 +36,6 @@ import com.google.inject.Inject;
  * Service responsible for kerberos related resource requests.
  */
 @StaticallyInject
-@Path("/kdc_check/")
 public class KdcServerReachabilityCheck {
   private static final String REACHABLE = "REACHABLE";
   private static final String UNREACHABLE = "UNREACHABLE";

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/AbstractVersionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AbstractVersionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AbstractVersionService.java
new file mode 100644
index 0000000..81df575
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AbstractVersionService.java
@@ -0,0 +1,352 @@
+/**
+ * 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.ambari.server.api.services;
+
+import org.apache.ambari.eventdb.webservice.WorkflowJsonService;
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.ambari.server.api.rest.BootStrapResource;
+import org.apache.ambari.server.api.rest.HealthCheck;
+import org.apache.ambari.server.api.rest.KdcServerReachabilityCheck;
+
+
+public abstract class AbstractVersionService {
+
+  /**
+   * Handles /actions request.
+   *
+   * @return action service
+   */
+  @Path("/actions")
+  public ActionService getActionService(@PathParam("apiVersion") String apiVersion) {
+    return new ActionService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /alert_targets request.
+   *
+   * @return alert targets service
+   */
+  @Path("/alert_targets")
+  public AlertTargetService getAlertTargetService(@PathParam("apiVersion") String apiVersion) {
+    return new AlertTargetService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /privileges request.
+   *
+   * @return privileges service
+   */
+  @Path("/privileges")
+  public AmbariPrivilegeService getAmbariPrivilegeService(@PathParam("apiVersion") String apiVersion) {
+    return new AmbariPrivilegeService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /blueprints request.
+   *
+   * @return blueprints service
+   */
+  @Path("/blueprints")
+  public BlueprintService getBlueprintService(@PathParam("apiVersion") String apiVersion) {
+    return new BlueprintService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /clusters request.
+   *
+   * @return cluster service
+   */
+  @Path("/clusters")
+  public ClusterService getClusterService(@PathParam("apiVersion") String apiVersion) {
+    return new ClusterService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /feeds request.
+   * TODO: Cleanup?
+   *
+   * @return feed service
+   */
+  @Path("/feeds")
+  public FeedService getFeedService(@PathParam("apiVersion") String apiVersion) {
+    return new FeedService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /groups request.
+   *
+   * @return group service
+   */
+  @Path("/groups")
+  public GroupService getGroupService(@PathParam("apiVersion") String apiVersion) {
+    return new GroupService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /hosts request.
+   *
+   * @return host service
+   */
+  @Path("/hosts")
+  public HostService getHostService(@PathParam("apiVersion") String apiVersion) {
+    return new HostService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /instances request.
+   * TODO: Cleanup?
+   *
+   * @return instance service
+   */
+  @Path("/instances")
+  public InstanceService getInstanceService(@PathParam("apiVersion") String apiVersion) {
+    return new InstanceService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /kerberos_descriptors request.
+   *
+   * @return kerberos descriptor service
+   */
+  @Path("/kerberos_descriptors")
+  public KerberosDescriptorService getKerberosDescriptorService(@PathParam("apiVersion") String apiVersion) {
+    return new KerberosDescriptorService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /keys request.
+   *
+   * @return key service
+   */
+  @Path("/keys")
+  public KeyService getKeyService(@PathParam("apiVersion") String apiVersion) {
+    return new KeyService();
+  }
+
+  /**
+   * Handles /ldap_sync_events request.
+   *
+   * @return Ldap sync event service
+   */
+  @Path("/ldap_sync_events")
+  public LdapSyncEventService getLdapSyncEventService(@PathParam("apiVersion") String apiVersion) {
+    return new LdapSyncEventService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /logout request.
+   *
+   * @return logout service
+   */
+  @Path("/logout")
+  public LogoutService getLogoutService(@PathParam("apiVersion") String apiVersion) {
+    return new LogoutService();
+  }
+
+  /**
+   * Handles /permissions request.
+   *
+   * @return permission service
+   */
+  @Path("/permissions")
+  public PermissionService getPermissionService(@PathParam("apiVersion") String apiVersion) {
+    return new PermissionService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /persist request.
+   *
+   * @return persist service
+   */
+  @Path("/persist")
+  public PersistKeyValueService getPersistKeyValueService(@PathParam("apiVersion") String apiVersion) {
+    return new PersistKeyValueService();
+  }
+
+  /**
+   * Handles /remoteclusters request
+   *
+   * @return remote clusters service
+   */
+  @Path("/remoteclusters")
+  public RemoteClustersService getRemoteClustersService(@PathParam("apiVersion") String apiVersion) {
+    return new RemoteClustersService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /requests request.
+   *
+   * @return request service
+   */
+  @Path("/requests")
+  public RequestService getRequestService(@PathParam("apiVersion") String apiVersion) {
+    return new RequestService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /settings request.
+   *
+   * @return request service
+   */
+  @Path("/settings")
+  public SettingService getSettingService(@PathParam("apiVersion") String apiVersion) {
+    return new SettingService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /authorizations request.
+   *
+   * @return role authorization service
+   */
+  @Path("/authorizations")
+  public RoleAuthorizationService getRoleAuthorizationService(@PathParam("apiVersion") String apiVersion) {
+    return new RoleAuthorizationService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /services request.
+   *
+   * @return root service service
+   */
+  @Path("/services")
+  public RootServiceService getRootServiceService(@PathParam("apiVersion") String apiVersion) {
+    return new RootServiceService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /targets request.
+   * TODO: Cleanup?
+   *
+   * @return target cluster service
+   */
+  @Path("/targets")
+  public TargetClusterService getTargetClusterService(@PathParam("apiVersion") String apiVersion) {
+    return new TargetClusterService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /users request.
+   *
+   * @return user service
+   */
+  @Path("/users")
+  public UserService getUserService(@PathParam("apiVersion") String apiVersion) {
+    return new UserService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /version_definitions request.
+   *
+   * @return version definition service
+   */
+  @Path("/version_definitions")
+  public VersionDefinitionService getVersionDefinitionService(@PathParam("apiVersion") String apiVersion) {
+    return new VersionDefinitionService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /views request.
+   *
+   * @return view service
+   */
+  @Path("/views")
+  public ViewService getViewService(@PathParam("apiVersion") String apiVersion) {
+    return new ViewService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /view/urls request.
+   *
+   * @return view urls service
+   */
+  @Path("/view/urls")
+  public ViewUrlsService getViewUrlsService(@PathParam("apiVersion") String apiVersion) {
+    return new ViewUrlsService(ApiVersion.valueOf(apiVersion));
+  }
+
+  /**
+   * Handles /stacks request.
+   *
+   * @return stacks service
+   */
+  @Path("/stacks")
+  public StacksService getStacksService(@PathParam("apiVersion") String apiVersion) {
+    return new StacksService(ApiVersion.valueOf(apiVersion));
+  }
+
+
+  /**
+   * Handles /bootstrap request.
+   *
+   * @return bootstrap service
+   */
+  @Path("/bootstrap")
+  public BootStrapResource getBootStrapResource(@PathParam("apiVersion") String apiVersion) {
+    return new BootStrapResource();
+  }
+
+
+  /**
+   * Handles /check request.
+   *
+   * @return health check service
+   */
+  @Path("/check")
+  public HealthCheck getHealthCheck(@PathParam("apiVersion") String apiVersion) {
+    return new HealthCheck();
+  }
+
+  /**
+   * Handles /kdc_check request.
+   *
+   * @return kdc server reachability service
+   */
+  @Path("/kdc_check")
+  public KdcServerReachabilityCheck getKdcServerReachabilityCheck(@PathParam("apiVersion") String apiVersion) {
+    return new KdcServerReachabilityCheck();
+  }
+
+  /**
+   * Handles /kdc_check request.
+   *
+   * @return kdc server reachability service
+   */
+  @Path("/jobhistory")
+  public WorkflowJsonService getWorkflowJsonService(@PathParam("apiVersion") String apiVersion) {
+    return new WorkflowJsonService();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ActionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ActionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ActionService.java
index 0126d3f..70b95f2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ActionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ActionService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -38,9 +39,12 @@ import java.util.Collections;
 /**
  * Service responsible for action definition resource requests.
  */
-@Path("/actions/")
 public class ActionService extends BaseService {
 
+  public ActionService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Handles: GET /actions/{actionName}
    * Get a specific action definition.

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ActiveWidgetLayoutService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ActiveWidgetLayoutService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ActiveWidgetLayoutService.java
index a0c3386..a84a6c1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ActiveWidgetLayoutService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ActiveWidgetLayoutService.java
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.GET;
@@ -39,7 +40,8 @@ public class ActiveWidgetLayoutService extends BaseService {
 
   private final String userName;
 
-  public ActiveWidgetLayoutService(String userName) {
+  public ActiveWidgetLayoutService(ApiVersion apiVersion, String userName) {
+    super(apiVersion);
     this.userName = userName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertDefinitionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertDefinitionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertDefinitionService.java
index e002c38..3c9de2f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertDefinitionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertDefinitionService.java
@@ -33,6 +33,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -42,7 +43,8 @@ public class AlertDefinitionService extends BaseService {
 
   private String clusterName = null;
 
-  AlertDefinitionService(String clusterName) {
+  AlertDefinitionService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     this.clusterName = clusterName;
   }
 
@@ -100,7 +102,7 @@ public class AlertDefinitionService extends BaseService {
   /**
    * Create a request schedule resource instance
    * @param clusterName
-   * @param requestScheduleId
+   * @param definitionId
    * @return
    */
   private ResourceInstance createResourceInstance(String clusterName,

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java
index a4bfcf3..07d3a42 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertGroupService.java
@@ -33,6 +33,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -51,7 +52,8 @@ public class AlertGroupService extends BaseService {
    *
    * @param clusterName
    */
-  AlertGroupService(String clusterName) {
+  AlertGroupService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     m_clusterName = clusterName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertHistoryService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertHistoryService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertHistoryService.java
index 4ebe1f6..9675e05 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertHistoryService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertHistoryService.java
@@ -30,6 +30,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -52,7 +53,8 @@ public class AlertHistoryService extends BaseService {
    * @param hostName
    *          the host name, or {@code null} to return history across all hosts.
    */
-  AlertHistoryService(String clusterName, String serviceName, String hostName) {
+  AlertHistoryService(ApiVersion apiVersion, String clusterName, String serviceName, String hostName) {
+    super(apiVersion);
     this.clusterName = clusterName;
     this.serviceName = serviceName;
     this.hostName = hostName;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertNoticeService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertNoticeService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertNoticeService.java
index 26731fb..e185443 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertNoticeService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertNoticeService.java
@@ -30,6 +30,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -45,7 +46,8 @@ public class AlertNoticeService extends BaseService {
    * @param clusterName
    *          the cluster name (not {@code null}).
    */
-  AlertNoticeService(String clusterName) {
+  AlertNoticeService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     this.clusterName = clusterName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java
index 184cbf1..541bed5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertService.java
@@ -30,6 +30,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -41,7 +42,8 @@ public class AlertService extends BaseService {
   private String serviceName = null;
   private String hostName = null;
 
-  AlertService(String clusterName, String serviceName, String hostName) {
+  AlertService(ApiVersion apiVersion, String clusterName, String serviceName, String hostName) {
+    super(apiVersion);
     this.clusterName = clusterName;
     this.serviceName = serviceName;
     this.hostName = hostName;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java
index 2e00491..ec7c295 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertTargetService.java
@@ -33,6 +33,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.state.alert.AlertTarget;
 
@@ -40,9 +41,12 @@ import org.apache.ambari.server.state.alert.AlertTarget;
  * The {@link AlertTargetService} handles CRUD operation requests for alert
  * targets.
  */
-@Path("/alert_targets/")
 public class AlertTargetService extends BaseService {
 
+  public AlertTargetService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   @GET
   @Produces("text/plain")
   public Response getTargets(@Context HttpHeaders headers,

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index c54fe3f..54a1fe7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -44,6 +44,8 @@ import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ParentObjectNotFoundException;
 import org.apache.ambari.server.StackAccessException;
 import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.AmbariServer;
 import org.apache.ambari.server.controller.RootServiceResponseFactory.Services;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.customactions.ActionDefinition;
@@ -55,6 +57,7 @@ import org.apache.ambari.server.metadata.AmbariServiceAlertDefinitions;
 import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
 import org.apache.ambari.server.orm.dao.MetainfoDAO;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.ClusterVersionEntity;
 import org.apache.ambari.server.orm.entities.MetainfoEntity;
 import org.apache.ambari.server.stack.StackDirectory;
 import org.apache.ambari.server.stack.StackManager;
@@ -218,6 +221,8 @@ public class AmbariMetaInfo {
    */
   private StackManager stackManager;
 
+  private AmbariManagementController controller;
+
   private Configuration conf;
 
   /**
@@ -241,6 +246,7 @@ public class AmbariMetaInfo {
     serverVersionFile = new File(serverVersionFilePath);
 
     customActionRoot = new File(conf.getCustomActionDefinitionPath());
+    controller = AmbariServer.getController();
   }
 
   /**
@@ -523,14 +529,15 @@ public class AmbariMetaInfo {
   }
 
   public ServiceInfo getService(String stackName, String version, String serviceName) throws AmbariException {
-    ServiceInfo service = getStack(stackName, version).getService(serviceName);
+    StackInfo stackInfo = getStack(stackName, version);
+    ServiceInfo serviceInfo = stackInfo.getService(serviceName);
 
-    if (service == null) {
+    if (serviceInfo == null) {
       throw new StackAccessException("stackName=" + stackName + ", stackVersion=" +
                                      version + ", serviceName=" + serviceName);
     }
 
-    return service;
+    return serviceInfo;
   }
 
   public Collection<String> getMonitoringServiceNames(String stackName, String version)

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariPrivilegeService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariPrivilegeService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariPrivilegeService.java
index db28f4f..9f8b0ba 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariPrivilegeService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariPrivilegeService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.Path;
@@ -27,8 +28,10 @@ import java.util.Collections;
 /**
  *  Service responsible for Ambari privilege resource requests.
  */
-@Path("/privileges/")
 public class AmbariPrivilegeService extends PrivilegeService {
+  public AmbariPrivilegeService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
 
   // ----- PrivilegeService --------------------------------------------------
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
index 139cf43..64263b5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
@@ -27,6 +27,7 @@ import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.CsvSerializer;
 import org.apache.ambari.server.api.services.serializers.JsonSerializer;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.audit.request.RequestAuditLogger;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.utils.RetryHelper;
@@ -41,6 +42,7 @@ import javax.ws.rs.core.UriInfo;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 import com.google.inject.Inject;
 
@@ -51,6 +53,12 @@ public abstract class BaseService {
   public final static MediaType MEDIA_TYPE_TEXT_CSV_TYPE = new MediaType("text", "csv");
 
   /**
+   * Regex for checking API version from the request URI
+   */
+  public static final Pattern API_VERSION_REGEX = Pattern.compile("^(/api/)(v[0-9\\.]+)");
+
+
+  /**
    * Logger instance.
    */
   protected final static Logger LOG = LoggerFactory.getLogger(BaseService.class);
@@ -67,6 +75,15 @@ public abstract class BaseService {
 
   protected static RequestAuditLogger requestAuditLogger;
 
+  /**
+   * Api version
+   */
+  protected ApiVersion m_apiVersion;
+
+  public BaseService(ApiVersion apiVersion) {
+    m_apiVersion = apiVersion;
+  }
+
   public static void init(RequestAuditLogger instance) {
     requestAuditLogger = instance;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/BlueprintService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BlueprintService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BlueprintService.java
index f40f858..c782311 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BlueprintService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BlueprintService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -39,9 +40,12 @@ import java.util.Collections;
  * any cluster specific information.  Updates are not permitted as blueprints are
  * immutable.
  */
-@Path("/blueprints/")
 public class BlueprintService extends BaseService {
 
+  public BlueprintService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Handles: GET  /blueprints
    * Get all blueprints.

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterKerberosDescriptorService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterKerberosDescriptorService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterKerberosDescriptorService.java
index 1452118..364a932 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterKerberosDescriptorService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterKerberosDescriptorService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.GET;
@@ -53,7 +54,8 @@ public class ClusterKerberosDescriptorService extends BaseService {
    *
    * @param clusterName cluster id
    */
-  public ClusterKerberosDescriptorService(String clusterName) {
+  public ClusterKerberosDescriptorService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     this.clusterName = clusterName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterPrivilegeService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterPrivilegeService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterPrivilegeService.java
index 11b4a46..86debb9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterPrivilegeService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterPrivilegeService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import java.util.HashMap;
@@ -42,7 +43,8 @@ public class ClusterPrivilegeService extends PrivilegeService {
    *
    * @param clusterName  the cluster name
    */
-  public ClusterPrivilegeService(String clusterName) {
+  public ClusterPrivilegeService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     this.clusterName = clusterName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
index 072c4a2..829efd8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
@@ -35,6 +35,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.AmbariServer;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.state.Clusters;
@@ -43,7 +44,6 @@ import org.apache.ambari.server.state.Clusters;
 /**
  * Service responsible for cluster resource requests.
  */
-@Path("/clusters/")
 public class ClusterService extends BaseService {
 
   /**
@@ -57,7 +57,8 @@ public class ClusterService extends BaseService {
   /**
    * Construct a ClusterService.
    */
-  public ClusterService() {
+  public ClusterService(ApiVersion apiVersion) {
+    super(apiVersion);
     clusters = AmbariServer.getController().getClusters();
   }
 
@@ -66,7 +67,8 @@ public class ClusterService extends BaseService {
    *
    * @param clusters  the clusters utilities
    */
-  protected ClusterService(Clusters clusters) {
+  protected ClusterService(ApiVersion apiVersion, Clusters clusters) {
+    super(apiVersion);
     this.clusters = clusters;
   }
 
@@ -326,7 +328,7 @@ public class ClusterService extends BaseService {
    */
   @Path("{clusterName}/hosts")
   public HostService getHostHandler(@Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
-    return new HostService(clusterName);
+    return new HostService(m_apiVersion, clusterName);
   }
 
   /**
@@ -339,7 +341,20 @@ public class ClusterService extends BaseService {
    */
   @Path("{clusterName}/services")
   public ServiceService getServiceHandler(@Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
-    return new ServiceService(clusterName);
+    return new ServiceService(m_apiVersion, clusterName);
+  }
+
+  /**
+   * Get the service groups sub-resource
+   *
+   * @param request      the request
+   * @param clusterName  cluster id
+   *
+   * @return the service groups service
+   */
+  @Path("{clusterName}/servicegroups")
+  public ServiceGroupService getServiceGroupHandler(@Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
+    return new ServiceGroupService(m_apiVersion, clusterName);
   }
 
   /**
@@ -352,7 +367,7 @@ public class ClusterService extends BaseService {
    */
   @Path("{clusterName}/configurations")
   public ConfigurationService getConfigurationHandler(@Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
-    return new ConfigurationService(clusterName);
+    return new ConfigurationService(m_apiVersion, clusterName);
   }
 
   /**
@@ -365,7 +380,7 @@ public class ClusterService extends BaseService {
    */
   @Path("{clusterName}/requests")
   public RequestService getRequestHandler(@Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
-    return new RequestService(clusterName);
+    return new RequestService(m_apiVersion, clusterName);
   }
 
   /**
@@ -379,7 +394,7 @@ public class ClusterService extends BaseService {
    */
   @Path("{clusterName}/host_components")
   public HostComponentService getHostComponentHandler(@Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
-    return new HostComponentService(clusterName, null);
+    return new HostComponentService(m_apiVersion, clusterName, null);
   }
 
   /**
@@ -393,7 +408,7 @@ public class ClusterService extends BaseService {
    */
   @Path("{clusterName}/kerberos_identities")
   public HostKerberosIdentityService getHostKerberosIdentityHandler(@Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
-    return new HostKerberosIdentityService(clusterName, null);
+    return new HostKerberosIdentityService(m_apiVersion, clusterName, null);
   }
 
   /**
@@ -407,7 +422,7 @@ public class ClusterService extends BaseService {
    */
   @Path("{clusterName}/components")
   public ComponentService getComponentHandler(@Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
-    return new ComponentService(clusterName, null);
+    return new ComponentService(m_apiVersion, clusterName, null);
   }
 
   /**
@@ -420,7 +435,7 @@ public class ClusterService extends BaseService {
    */
   @Path("{clusterName}/workflows")
   public WorkflowService getWorkflowHandler(@Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
-    return new WorkflowService(clusterName);
+    return new WorkflowService(m_apiVersion, clusterName);
   }
 
   /**
@@ -433,7 +448,7 @@ public class ClusterService extends BaseService {
    */
   @Path("{clusterName}/config_groups")
   public ConfigGroupService getConfigGroupService(@Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
-    return new ConfigGroupService(clusterName);
+    return new ConfigGroupService(m_apiVersion, clusterName);
   }
 
   /**
@@ -447,7 +462,7 @@ public class ClusterService extends BaseService {
   @Path("{clusterName}/request_schedules")
   public RequestScheduleService getRequestScheduleService
                              (@Context javax.ws.rs.core.Request request, @PathParam ("clusterName") String clusterName) {
-    return new RequestScheduleService(clusterName);
+    return new RequestScheduleService(m_apiVersion, clusterName);
   }
 
   /**
@@ -461,7 +476,7 @@ public class ClusterService extends BaseService {
   @Path("{clusterName}/alert_definitions")
   public AlertDefinitionService getAlertDefinitionService(
       @Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
-    return new AlertDefinitionService(clusterName);
+    return new AlertDefinitionService(m_apiVersion, clusterName);
   }
 
   /**
@@ -477,7 +492,7 @@ public class ClusterService extends BaseService {
   public AlertGroupService getAlertGroups(
       @Context javax.ws.rs.core.Request request,
       @PathParam("clusterName") String clusterName) {
-    return new AlertGroupService(clusterName);
+    return new AlertGroupService(m_apiVersion, clusterName);
   }
 
   /**
@@ -492,7 +507,7 @@ public class ClusterService extends BaseService {
    */
   @Path("{clusterName}/privileges")
   public PrivilegeService getPrivilegeService(@Context javax.ws.rs.core.Request request, @PathParam ("clusterName") String clusterName) {
-    return new ClusterPrivilegeService(clusterName);
+    return new ClusterPrivilegeService(m_apiVersion, clusterName);
   }
 
   /**
@@ -506,7 +521,7 @@ public class ClusterService extends BaseService {
   @Path("{clusterName}/alerts")
   public AlertService getAlertService(
       @Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
-    return new AlertService(clusterName, null, null);
+    return new AlertService(m_apiVersion, clusterName, null, null);
   }
 
   /**
@@ -523,7 +538,7 @@ public class ClusterService extends BaseService {
   public AlertHistoryService getAlertHistoryService(
       @Context javax.ws.rs.core.Request request,
       @PathParam("clusterName") String clusterName) {
-    return new AlertHistoryService(clusterName, null, null);
+    return new AlertHistoryService(m_apiVersion, clusterName, null, null);
   }
 
   /**
@@ -540,7 +555,7 @@ public class ClusterService extends BaseService {
   public AlertNoticeService getAlertNoticeService(
       @Context javax.ws.rs.core.Request request,
       @PathParam("clusterName") String clusterName) {
-    return new AlertNoticeService(clusterName);
+    return new AlertNoticeService(m_apiVersion, clusterName);
   }
 
   /**
@@ -556,7 +571,7 @@ public class ClusterService extends BaseService {
   @Path("{clusterName}/stack_versions")
   public ClusterStackVersionService getClusterStackVersionService(@Context javax.ws.rs.core.Request request,
       @PathParam("clusterName") String clusterName) {
-    return new ClusterStackVersionService(clusterName);
+    return new ClusterStackVersionService(m_apiVersion, clusterName);
   }
 
   /**
@@ -571,7 +586,7 @@ public class ClusterService extends BaseService {
   public UpgradeService getUpgradeService(
       @Context javax.ws.rs.core.Request request,
       @PathParam("clusterName") String clusterName) {
-    return new UpgradeService(clusterName);
+    return new UpgradeService(m_apiVersion, clusterName);
   }
 
   /**
@@ -586,7 +601,7 @@ public class ClusterService extends BaseService {
   public UpgradeSummaryService getUpgradeSummaryService(
       @Context javax.ws.rs.core.Request request,
       @PathParam("clusterName") String clusterName) {
-    return new UpgradeSummaryService(clusterName);
+    return new UpgradeSummaryService(m_apiVersion, clusterName);
   }
   
   /**
@@ -599,7 +614,7 @@ public class ClusterService extends BaseService {
    */
   @Path("{clusterName}/rolling_upgrades_check")
   public PreUpgradeCheckService getPreUpgradeCheckService(@Context javax.ws.rs.core.Request request, @PathParam("clusterName") String clusterName) {
-    return new PreUpgradeCheckService(clusterName);
+    return new PreUpgradeCheckService(m_apiVersion, clusterName);
   }
 
   /**
@@ -609,7 +624,7 @@ public class ClusterService extends BaseService {
   public WidgetLayoutService getWidgetLayoutService(@Context javax.ws.rs.core.Request request,
                                                     @PathParam ("clusterName") String clusterName) {
 
-    return new WidgetLayoutService(clusterName);
+    return new WidgetLayoutService(m_apiVersion, clusterName);
   }
 
   /**
@@ -619,7 +634,7 @@ public class ClusterService extends BaseService {
   public WidgetService getWidgetService(@Context javax.ws.rs.core.Request request,
                                                     @PathParam ("clusterName") String clusterName) {
 
-    return new WidgetService(clusterName);
+    return new WidgetService(m_apiVersion, clusterName);
   }
 
   /**
@@ -633,7 +648,7 @@ public class ClusterService extends BaseService {
   public CredentialService getCredentials(
       @Context javax.ws.rs.core.Request request,
       @PathParam("clusterName") String clusterName) {
-    return new CredentialService(clusterName);
+    return new CredentialService(m_apiVersion, clusterName);
   }
 
   /**
@@ -648,7 +663,7 @@ public class ClusterService extends BaseService {
   public ClusterKerberosDescriptorService getCompositeKerberosDescriptor(
       @Context javax.ws.rs.core.Request request,
       @PathParam("clusterName") String clusterName) {
-    return new ClusterKerberosDescriptorService(clusterName);
+    return new ClusterKerberosDescriptorService(m_apiVersion, clusterName);
   }
 
   /**
@@ -662,7 +677,7 @@ public class ClusterService extends BaseService {
   @Path("{clusterName}/logging")
   public LoggingService getLogging(@Context javax.ws.rs.core.Request request,
                                    @PathParam("clusterName") String clusterName) {
-    return new LoggingService(clusterName);
+    return new LoggingService(m_apiVersion, clusterName);
   }
 
   // ----- helper methods ----------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterStackVersionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterStackVersionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterStackVersionService.java
index e3150b0..3880bbc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterStackVersionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterStackVersionService.java
@@ -32,6 +32,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -48,7 +49,8 @@ public class ClusterStackVersionService extends BaseService {
    *
    * @param clusterName name of the cluster
    */
-  public ClusterStackVersionService(String clusterName) {
+  public ClusterStackVersionService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     this.clusterName = clusterName;
   }
 
@@ -102,7 +104,7 @@ public class ClusterStackVersionService extends BaseService {
     final Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
     mapIds.put(Resource.Type.Cluster, clusterName);
     mapIds.put(Resource.Type.ClusterStackVersion, stackVersion);
-    return new RepositoryVersionService(mapIds);
+    return new RepositoryVersionService(m_apiVersion, mapIds);
   }
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/CompatibleRepositoryVersionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/CompatibleRepositoryVersionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/CompatibleRepositoryVersionService.java
index 12d6433..6e4d202 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/CompatibleRepositoryVersionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/CompatibleRepositoryVersionService.java
@@ -30,6 +30,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -47,7 +48,8 @@ public class CompatibleRepositoryVersionService extends BaseService {
    *
    * @param parentProperties extra properties to be inserted into created resource
    */
-  public CompatibleRepositoryVersionService(Map<Resource.Type, String> parentProperties) {
+  public CompatibleRepositoryVersionService(ApiVersion apiVersion, Map<Resource.Type, String> parentProperties) {
+    super(apiVersion);
     parentKeyProperties = parentProperties;
   }
 
@@ -94,7 +96,7 @@ public class CompatibleRepositoryVersionService extends BaseService {
     mapIds.putAll(parentKeyProperties);
     mapIds.put(Resource.Type.CompatibleRepositoryVersion, repositoryVersionId);
 
-    return new OperatingSystemService(mapIds);
+    return new OperatingSystemService(m_apiVersion, mapIds);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ComponentService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ComponentService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ComponentService.java
index e7e0029..2fca698 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ComponentService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ComponentService.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services;
 
 import com.google.inject.Inject;
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.spi.ClusterController;
 import org.apache.ambari.server.controller.spi.Resource;
@@ -56,7 +57,8 @@ public class ComponentService extends BaseService {
    * @param clusterName cluster id
    * @param serviceName service id
    */
-  public ComponentService(String clusterName, String serviceName) {
+  public ComponentService(ApiVersion apiVersion, String clusterName, String serviceName) {
+    super(apiVersion);
     m_clusterName = clusterName;
     m_serviceName = serviceName;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigGroupService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigGroupService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigGroupService.java
index 39f1f55..46ce7c3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigGroupService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigGroupService.java
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -47,7 +48,8 @@ public class ConfigGroupService extends BaseService {
    * Constructor
    * @param m_clusterName
    */
-  public ConfigGroupService(String m_clusterName) {
+  public ConfigGroupService(ApiVersion apiVersion, String m_clusterName) {
+    super(apiVersion);
     this.m_clusterName = m_clusterName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigurationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigurationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigurationService.java
index cfbfc7f..83a12f9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigurationService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ConfigurationService.java
@@ -28,6 +28,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import java.util.HashMap;
@@ -47,13 +48,14 @@ public class ConfigurationService extends BaseService {
    *
    * @param clusterName cluster id
    */
-  public ConfigurationService(String clusterName) {
+  public ConfigurationService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     m_clusterName = clusterName;
   }
 
   @Path("service_config_versions")
   public ServiceConfigVersionService getServiceConfigVersionService() {
-    return new ServiceConfigVersionService(m_clusterName);
+    return new ServiceConfigVersionService(m_apiVersion, m_clusterName);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/CredentialService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/CredentialService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/CredentialService.java
index 01f8e8f..7604397 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/CredentialService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/CredentialService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -42,7 +43,8 @@ public class CredentialService extends BaseService {
 
   private final String clusterName;
 
-  public CredentialService(String clusterName) {
+  public CredentialService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     this.clusterName = clusterName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/FeedService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/FeedService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/FeedService.java
index 6741303..5919f1d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/FeedService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/FeedService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -37,9 +38,12 @@ import java.util.Collections;
 /**
  * DR feed service.
  */
-@Path("/feeds/")
 public class FeedService extends BaseService {
 
+  public FeedService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Handles: GET /feeds/{feedName}
    * Get a specific feed.
@@ -134,7 +138,7 @@ public class FeedService extends BaseService {
    */
   @Path("{feedName}/instances")
   public InstanceService getHostHandler(@PathParam("feedName") String feedName) {
-    return new InstanceService(feedName);
+    return new InstanceService(m_apiVersion, feedName);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/GroupPrivilegeService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/GroupPrivilegeService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/GroupPrivilegeService.java
index 290d488..5afd459 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/GroupPrivilegeService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/GroupPrivilegeService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.servlet.http.HttpServletResponse;
@@ -35,7 +36,8 @@ public class GroupPrivilegeService extends PrivilegeService {
 
   private final String groupName;
 
-  public GroupPrivilegeService(String groupName) {
+  public GroupPrivilegeService(ApiVersion apiVersion, String groupName) {
+    super(apiVersion);
     this.groupName = groupName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/GroupService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/GroupService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/GroupService.java
index 7ecd87f..bf24cf1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/GroupService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/GroupService.java
@@ -29,6 +29,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import java.util.Collections;
@@ -36,8 +37,11 @@ import java.util.Collections;
 /**
  * Service responsible for user groups requests.
  */
-@Path("/groups/")
 public class GroupService extends BaseService {
+  public GroupService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Gets all groups.
    * Handles: GET /groups requests.
@@ -127,7 +131,7 @@ public class GroupService extends BaseService {
    */
   @Path("{groupName}/members")
   public MemberService getMemberHandler(@PathParam("groupName") String groupName) {
-    return new MemberService(groupName);
+    return new MemberService(m_apiVersion, groupName);
   }
 
   /**
@@ -137,7 +141,7 @@ public class GroupService extends BaseService {
   public PrivilegeService getPrivilegeService(@Context javax.ws.rs.core.Request request,
                                               @PathParam ("groupName") String groupName) {
 
-    return new GroupPrivilegeService(groupName);
+    return new GroupPrivilegeService(m_apiVersion, groupName);
   }
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostComponentService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostComponentService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostComponentService.java
index 4990ad7..4631e63 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostComponentService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostComponentService.java
@@ -32,6 +32,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.spi.Resource;
 
@@ -55,7 +56,8 @@ public class HostComponentService extends BaseService {
    * @param clusterName cluster id
    * @param hostName    host id
    */
-  public HostComponentService(String clusterName, String hostName) {
+  public HostComponentService(ApiVersion apiVersion, String clusterName, String hostName) {
+    super(apiVersion);
     m_clusterName = clusterName;
     m_hostName = hostName;
   }
@@ -249,6 +251,7 @@ public class HostComponentService extends BaseService {
     Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
     mapIds.put(Resource.Type.Cluster, clusterName);
     mapIds.put(Resource.Type.Host, hostName);
+    mapIds.put(Resource.Type.Service, null);
     mapIds.put(Resource.Type.HostComponent, hostComponentName);
 
     return createResource(Resource.Type.HostComponent, mapIds);
@@ -259,6 +262,7 @@ public class HostComponentService extends BaseService {
     Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
     mapIds.put(Resource.Type.Cluster, m_clusterName);
     mapIds.put(Resource.Type.Host, m_hostName);
+    mapIds.put(Resource.Type.Service, null);
     mapIds.put(Resource.Type.Component, hostComponentName);
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostKerberosIdentityService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostKerberosIdentityService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostKerberosIdentityService.java
index 624a335..5c0ffca 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostKerberosIdentityService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostKerberosIdentityService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.GET;
@@ -55,7 +56,8 @@ public class HostKerberosIdentityService extends BaseService {
    * @param clusterName cluster name
    * @param hostName    host name
    */
-  public HostKerberosIdentityService(String clusterName, String hostName) {
+  public HostKerberosIdentityService(ApiVersion apiVersion, String clusterName, String hostName) {
+    super(apiVersion);
     this.clusterName = clusterName;
     this.hostName = hostName;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java
index 0ce29ae..c8225a8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostService.java
@@ -34,12 +34,12 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
  * Service responsible for hosts resource requests.
  */
-@Path("/hosts/")
 public class HostService extends BaseService {
 
   /**
@@ -50,7 +50,8 @@ public class HostService extends BaseService {
   /**
    * Constructor.
    */
-  public HostService() {
+  public HostService(ApiVersion apiVersion) {
+    super(apiVersion);
   }
 
   /**
@@ -58,7 +59,8 @@ public class HostService extends BaseService {
    *
    * @param clusterName cluster id
    */
-  public HostService(String clusterName) {
+  public HostService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     m_clusterName = clusterName;
   }
 
@@ -211,7 +213,7 @@ public class HostService extends BaseService {
    */
   @Path("{hostName}/host_components")
   public HostComponentService getHostComponentHandler(@PathParam("hostName") String hostName) {
-    return new HostComponentService(m_clusterName, hostName);
+    return new HostComponentService(m_apiVersion, m_clusterName, hostName);
   }
 
   /**
@@ -222,7 +224,7 @@ public class HostService extends BaseService {
    */
   @Path("{hostName}/kerberos_identities")
   public HostKerberosIdentityService getHostKerberosIdentityHandler(@PathParam("hostName") String hostName) {
-    return new HostKerberosIdentityService(m_clusterName, hostName);
+    return new HostKerberosIdentityService(m_apiVersion, m_clusterName, hostName);
   }
 
   /**
@@ -233,7 +235,7 @@ public class HostService extends BaseService {
    */
   @Path("{hostName}/alerts")
   public AlertService getAlertHandler(@PathParam("hostName") String hostName) {
-    return new AlertService(m_clusterName, null, hostName);
+    return new AlertService(m_apiVersion, m_clusterName, null, hostName);
   }
 
   /**
@@ -251,7 +253,7 @@ public class HostService extends BaseService {
       @Context javax.ws.rs.core.Request request,
       @PathParam("hostName") String hostName) {
 
-    return new AlertHistoryService(m_clusterName, null, hostName);
+    return new AlertHistoryService(m_apiVersion, m_clusterName, null, hostName);
   }
 
   /**
@@ -268,7 +270,7 @@ public class HostService extends BaseService {
   public HostStackVersionService getHostStackVersionService(@Context javax.ws.rs.core.Request request,
       @PathParam("hostName") String hostName) {
 
-    return new HostStackVersionService(hostName, m_clusterName);
+    return new HostStackVersionService(m_apiVersion, hostName, m_clusterName);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostStackVersionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostStackVersionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostStackVersionService.java
index f449052..331c920 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostStackVersionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/HostStackVersionService.java
@@ -31,6 +31,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -52,7 +53,8 @@ public class HostStackVersionService extends BaseService {
    *
    * @param hostName name of the host
    */
-  public HostStackVersionService(String hostName, String clusterName) {
+  public HostStackVersionService(ApiVersion apiVersion, String hostName, String clusterName) {
+    super(apiVersion);
     this.hostName = hostName;
     this.clusterName = clusterName;
   }
@@ -116,7 +118,7 @@ public class HostStackVersionService extends BaseService {
     final Map<Resource.Type, String> stackVersionProperties = new HashMap<Resource.Type, String>();
     stackVersionProperties.put(Resource.Type.Host, hostName);
     stackVersionProperties.put(Resource.Type.HostStackVersion, stackVersionId);
-    return new RepositoryVersionService(stackVersionProperties);
+    return new RepositoryVersionService(m_apiVersion, stackVersionProperties);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/InstanceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/InstanceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/InstanceService.java
index e771ccc..62531f1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/InstanceService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/InstanceService.java
@@ -31,6 +31,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import java.util.HashMap;
@@ -39,7 +40,6 @@ import java.util.Map;
 /**
  * Service responsible for instances resource requests.
  */
-@Path("/instances/")
 public class InstanceService extends BaseService {
 
   /**
@@ -50,7 +50,8 @@ public class InstanceService extends BaseService {
   /**
    * Constructor.
    */
-  public InstanceService() {
+  public InstanceService(ApiVersion apiVersion) {
+    super(apiVersion);
   }
 
   /**
@@ -58,7 +59,8 @@ public class InstanceService extends BaseService {
    *
    * @param feedName feed id
    */
-  public InstanceService(String feedName) {
+  public InstanceService(ApiVersion apiVersion, String feedName) {
+    super(apiVersion);
     m_feedName = feedName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/JobService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/JobService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/JobService.java
index ab4b635..94a21c3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/JobService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/JobService.java
@@ -31,6 +31,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -48,7 +49,8 @@ public class JobService extends BaseService {
    * @param workflowId
    *          workflow id
    */
-  public JobService(String clusterName, String workflowId) {
+  public JobService(ApiVersion apiVersion, String clusterName, String workflowId) {
+    super(apiVersion);
     this.clusterName = clusterName;
     this.workflowId = workflowId;
   }
@@ -95,7 +97,7 @@ public class JobService extends BaseService {
   @Path("{jobId}/taskattempts")
   public TaskAttemptService getTaskAttemptHandler(
       @PathParam("jobId") String jobId) {
-    return new TaskAttemptService(clusterName, workflowId, jobId);
+    return new TaskAttemptService(m_apiVersion, clusterName, workflowId, jobId);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/KerberosDescriptorService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/KerberosDescriptorService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/KerberosDescriptorService.java
index 91e1dc5..a14bb2c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/KerberosDescriptorService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/KerberosDescriptorService.java
@@ -1,6 +1,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -33,9 +34,12 @@ import java.util.Collections;
  * limitations under the License.
  */
 
-@Path("/kerberos_descriptors/")
 public class KerberosDescriptorService extends BaseService {
 
+  public KerberosDescriptorService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Handles: GET  /kerberos_descriptors
    * Get all kerberos descriptors.

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/KeyService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/KeyService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/KeyService.java
index 6d2d22f..bd44374 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/KeyService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/KeyService.java
@@ -30,7 +30,6 @@ import javax.xml.bind.JAXBException;
 import java.io.IOException;
 import java.util.Collection;
 
-@Path("/keys/")
 public class KeyService {
   private static final Logger log = LoggerFactory.getLogger(KeyService.class);
   private static PersistKeyValueImpl persistKeyVal;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/LdapSyncEventService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LdapSyncEventService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LdapSyncEventService.java
index bf4bcff..3b50c42 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LdapSyncEventService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LdapSyncEventService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -37,8 +38,11 @@ import java.util.Collections;
 /**
  * Service responsible for ldap sync event resource requests.
  */
-@Path("/ldap_sync_events/")
 public class LdapSyncEventService extends BaseService {
+  public LdapSyncEventService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Handles: GET /ldap_sync_events/{eventId}
    * Get a specific view.

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java
index c93f7bd..75e5fb0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LoggingService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.AmbariServer;
 import org.apache.ambari.server.controller.internal.ResourceImpl;
@@ -58,11 +59,13 @@ public class LoggingService extends BaseService {
 
   private final String clusterName;
 
-  public LoggingService(String clusterName) {
-    this(clusterName, new DefaultControllerFactory(), new LoggingRequestHelperFactoryImpl());
+  public LoggingService(ApiVersion apiVersion, String clusterName) {
+    this(apiVersion, clusterName, new DefaultControllerFactory(), new LoggingRequestHelperFactoryImpl());
   }
 
-  public LoggingService(String clusterName, ControllerFactory controllerFactory, LoggingRequestHelperFactory helperFactory) {
+  public LoggingService(ApiVersion apiVersion, String clusterName, ControllerFactory controllerFactory,
+                        LoggingRequestHelperFactory helperFactory) {
+    super(apiVersion);
     this.clusterName = clusterName;
     this.controllerFactory = controllerFactory;
     this.helperFactory = helperFactory;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java
index 02403f9..4e1e831 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java
@@ -37,7 +37,6 @@ import org.springframework.security.core.context.SecurityContextHolder;
  * Service performing logout of current user
  */
 @StaticallyInject
-@Path("/logout")
 public class LogoutService {
 
   @Inject

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/MemberService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/MemberService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/MemberService.java
index 28e53e6..8b01ea3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/MemberService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/MemberService.java
@@ -33,6 +33,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -49,7 +50,8 @@ public class MemberService extends BaseService {
    *
    * @param groupName name of the group
    */
-  public MemberService(String groupName) {
+  public MemberService(ApiVersion apiVersion, String groupName) {
+    super(apiVersion);
     this.groupName = groupName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/OperatingSystemService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/OperatingSystemService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/OperatingSystemService.java
index 531f964..0ea548d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/OperatingSystemService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/OperatingSystemService.java
@@ -47,6 +47,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -64,7 +65,8 @@ public class OperatingSystemService extends BaseService {
    *
    * @param parentKeyProperties extra properties to be inserted into created resource
    */
-  public OperatingSystemService(Map<Resource.Type, String> parentKeyProperties) {
+  public OperatingSystemService(ApiVersion apiVersion, Map<Resource.Type, String> parentKeyProperties) {
+    super(apiVersion);
     this.parentKeyProperties = parentKeyProperties;
   }
 
@@ -108,7 +110,7 @@ public class OperatingSystemService extends BaseService {
     final Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
     mapIds.putAll(parentKeyProperties);
     mapIds.put(Resource.Type.OperatingSystem, osType);
-    return new RepositoryService(mapIds);
+    return new RepositoryService(m_apiVersion, mapIds);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/PermissionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/PermissionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/PermissionService.java
index 3a1a875..3ddb53f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/PermissionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/PermissionService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -38,9 +39,12 @@ import java.util.Collections;
 /**
  * Service responsible for permission resource requests.
  */
-@Path("/permissions/")
 public class PermissionService extends BaseService {
 
+  public PermissionService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Handles: GET /permissions/{permissionID}
    * Get a specific permission.
@@ -142,7 +146,7 @@ public class PermissionService extends BaseService {
   @Path("{permissionId}/authorizations")
   public RoleAuthorizationService getRoleAuthorizations(
       @Context javax.ws.rs.core.Request request, @PathParam("permissionId") String permissionId) {
-    return new RoleAuthorizationService(permissionId);
+    return new RoleAuthorizationService(m_apiVersion, permissionId);
   }
 
   // ----- helper methods ----------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/PersistKeyValueService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/PersistKeyValueService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/PersistKeyValueService.java
index 83217c5..fa12be6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/PersistKeyValueService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/PersistKeyValueService.java
@@ -40,7 +40,6 @@ import org.apache.commons.logging.LogFactory;
 
 import com.google.inject.Inject;
 
-@Path("/persist/")
 public class PersistKeyValueService {
   private static PersistKeyValueImpl persistKeyVal;
   private static Log LOG = LogFactory.getLog(PersistKeyValueService.class);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/PreUpgradeCheckService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/PreUpgradeCheckService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/PreUpgradeCheckService.java
index 0525b3a..d834227 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/PreUpgradeCheckService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/PreUpgradeCheckService.java
@@ -27,6 +27,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -44,7 +45,8 @@ public class PreUpgradeCheckService extends BaseService {
    *
    * @param clusterName cluster name
    */
-  public PreUpgradeCheckService(String clusterName) {
+  public PreUpgradeCheckService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     this.clusterName = clusterName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/PrivilegeService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/PrivilegeService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/PrivilegeService.java
index 2caa5d2..2f52ae7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/PrivilegeService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/PrivilegeService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -38,6 +39,10 @@ import javax.ws.rs.core.UriInfo;
  */
 public abstract class PrivilegeService extends BaseService {
 
+  public PrivilegeService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Handles: GET /privileges/{privilegeID}
    * Get a specific privilege.

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/RecommendationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RecommendationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RecommendationService.java
deleted file mode 100644
index 23248b3..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RecommendationService.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * 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.ambari.server.api.services;
-
-import java.util.HashMap;
-import java.util.Map;
-
-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.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.ambari.server.api.resources.ResourceInstance;
-import org.apache.ambari.server.controller.spi.Resource;
-
-/**
- * Service responsible for preparing recommendations for host-layout and
- * configurations.
- */
-@Path("/stacks/{stackName}/versions/{stackVersion}/recommendations")
-public class RecommendationService extends BaseService {
-
-  /**
-   * Returns host-layout recommendations for list of hosts and services.
-   * 
-   * @param body http body
-   * @param headers http headers
-   * @param ui uri info
-   * @param stackName stack name
-   * @param stackVersion stack version
-   * @return recommendations for host-layout
-   */
-  @POST
-  @Produces(MediaType.TEXT_PLAIN)
-  public Response getRecommendation(String body, @Context HttpHeaders headers, @Context UriInfo ui,
-      @PathParam("stackName") String stackName, @PathParam("stackVersion") String stackVersion) {
-
-    return handleRequest(headers, body, ui, Request.Type.POST,
-        createRecommendationResource(stackName, stackVersion));
-  }
-
-  ResourceInstance createRecommendationResource(String stackName, String stackVersion) {
-    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
-    mapIds.put(Resource.Type.Stack, stackName);
-    mapIds.put(Resource.Type.StackVersion, stackVersion);
-
-    return createResource(Resource.Type.Recommendation, mapIds);
-  }
-
-}


[03/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/codemirror.css
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/codemirror.css b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/codemirror.css
new file mode 100644
index 0000000..68c67b1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/codemirror.css
@@ -0,0 +1,309 @@
+/* BASICS */
+
+.CodeMirror {
+  /* Set height, width, borders, and global font properties here */
+  font-family: monospace;
+  height: 300px;
+}
+.CodeMirror-scroll {
+  /* Set scrolling behaviour here */
+  overflow: auto;
+}
+
+/* PADDING */
+
+.CodeMirror-lines {
+  padding: 4px 0; /* Vertical padding around content */
+}
+.CodeMirror pre {
+  padding: 0 4px; /* Horizontal padding of content */
+}
+
+.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+  background-color: white; /* The little square between H and V scrollbars */
+}
+
+/* GUTTER */
+
+.CodeMirror-gutters {
+  border-right: 1px solid #ddd;
+  background-color: #f7f7f7;
+  white-space: nowrap;
+}
+.CodeMirror-linenumbers {}
+.CodeMirror-linenumber {
+  padding: 0 3px 0 5px;
+  min-width: 20px;
+  text-align: right;
+  color: #999;
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+
+.CodeMirror-guttermarker { color: black; }
+.CodeMirror-guttermarker-subtle { color: #999; }
+
+/* CURSOR */
+
+.CodeMirror div.CodeMirror-cursor {
+  border-left: 1px solid black;
+}
+/* Shown when moving in bi-directional text */
+.CodeMirror div.CodeMirror-secondarycursor {
+  border-left: 1px solid silver;
+}
+.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
+  width: auto;
+  border: 0;
+  background: #7e7;
+}
+.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursors {
+  z-index: 1;
+}
+
+.cm-animate-fat-cursor {
+  width: auto;
+  border: 0;
+  -webkit-animation: blink 1.06s steps(1) infinite;
+  -moz-animation: blink 1.06s steps(1) infinite;
+  animation: blink 1.06s steps(1) infinite;
+}
+@-moz-keyframes blink {
+  0% { background: #7e7; }
+  50% { background: none; }
+  100% { background: #7e7; }
+}
+@-webkit-keyframes blink {
+  0% { background: #7e7; }
+  50% { background: none; }
+  100% { background: #7e7; }
+}
+@keyframes blink {
+  0% { background: #7e7; }
+  50% { background: none; }
+  100% { background: #7e7; }
+}
+
+/* Can style cursor different in overwrite (non-insert) mode */
+div.CodeMirror-overwrite div.CodeMirror-cursor {}
+
+.cm-tab { display: inline-block; text-decoration: inherit; }
+
+.CodeMirror-ruler {
+  border-left: 1px solid #ccc;
+  position: absolute;
+}
+
+/* DEFAULT THEME */
+
+.cm-s-default .cm-keyword {color: #708;}
+.cm-s-default .cm-atom {color: #219;}
+.cm-s-default .cm-number {color: #164;}
+.cm-s-default .cm-def {color: #00f;}
+.cm-s-default .cm-variable,
+.cm-s-default .cm-punctuation,
+.cm-s-default .cm-property,
+.cm-s-default .cm-operator {}
+.cm-s-default .cm-variable-2 {color: #05a;}
+.cm-s-default .cm-variable-3 {color: #085;}
+.cm-s-default .cm-comment {color: #a50;}
+.cm-s-default .cm-string {color: #a11;}
+.cm-s-default .cm-string-2 {color: #f50;}
+.cm-s-default .cm-meta {color: #555;}
+.cm-s-default .cm-qualifier {color: #555;}
+.cm-s-default .cm-builtin {color: #30a;}
+.cm-s-default .cm-bracket {color: #997;}
+.cm-s-default .cm-tag {color: #170;}
+.cm-s-default .cm-attribute {color: #00c;}
+.cm-s-default .cm-header {color: blue;}
+.cm-s-default .cm-quote {color: #090;}
+.cm-s-default .cm-hr {color: #999;}
+.cm-s-default .cm-link {color: #00c;}
+
+.cm-negative {color: #d44;}
+.cm-positive {color: #292;}
+.cm-header, .cm-strong {font-weight: bold;}
+.cm-em {font-style: italic;}
+.cm-link {text-decoration: underline;}
+
+.cm-s-default .cm-error {color: #f00;}
+.cm-invalidchar {color: #f00;}
+
+/* Default styles for common addons */
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
+.CodeMirror-activeline-background {background: #e8f2ff;}
+
+/* STOP */
+
+/* The rest of this file contains styles related to the mechanics of
+   the editor. You probably shouldn't touch them. */
+
+.CodeMirror {
+  line-height: 1;
+  position: relative;
+  overflow: hidden;
+  background: white;
+  color: black;
+}
+
+.CodeMirror-scroll {
+  /* 30px is the magic margin used to hide the element's real scrollbars */
+  /* See overflow: hidden in .CodeMirror */
+  margin-bottom: -30px; margin-right: -30px;
+  padding-bottom: 30px;
+  height: 100%;
+  outline: none; /* Prevent dragging from highlighting the element */
+  position: relative;
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+.CodeMirror-sizer {
+  position: relative;
+  border-right: 30px solid transparent;
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+   before actuall scrolling happens, thus preventing shaking and
+   flickering artifacts. */
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+  position: absolute;
+  z-index: 6;
+  display: none;
+}
+.CodeMirror-vscrollbar {
+  right: 0; top: 0;
+  overflow-x: hidden;
+  overflow-y: scroll;
+}
+.CodeMirror-hscrollbar {
+  bottom: 0; left: 0;
+  overflow-y: hidden;
+  overflow-x: scroll;
+}
+.CodeMirror-scrollbar-filler {
+  right: 0; bottom: 0;
+}
+.CodeMirror-gutter-filler {
+  left: 0; bottom: 0;
+}
+
+.CodeMirror-gutters {
+  position: absolute; left: 0; top: 0;
+  padding-bottom: 30px;
+  z-index: 3;
+}
+.CodeMirror-gutter {
+  white-space: normal;
+  height: 100%;
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+  padding-bottom: 30px;
+  margin-bottom: -32px;
+  display: inline-block;
+  /* Hack to make IE7 behave */
+  *zoom:1;
+  *display:inline;
+}
+.CodeMirror-gutter-elt {
+  position: absolute;
+  cursor: default;
+  z-index: 4;
+}
+
+.CodeMirror-lines {
+  cursor: text;
+  min-height: 1px; /* prevents collapsing before first draw */
+}
+.CodeMirror pre {
+  /* Reset some styles that the rest of the page might have set */
+  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
+  border-width: 0;
+  background: transparent;
+  font-family: inherit;
+  font-size: inherit;
+  margin: 0;
+  white-space: pre;
+  word-wrap: normal;
+  line-height: inherit;
+  color: inherit;
+  z-index: 2;
+  position: relative;
+  overflow: visible;
+}
+.CodeMirror-wrap pre {
+  word-wrap: break-word;
+  white-space: pre-wrap;
+  word-break: normal;
+}
+
+.CodeMirror-linebackground {
+  position: absolute;
+  left: 0; right: 0; top: 0; bottom: 0;
+  z-index: 0;
+}
+
+.CodeMirror-linewidget {
+  position: relative;
+  z-index: 2;
+  overflow: auto;
+}
+
+.CodeMirror-widget {}
+
+.CodeMirror-wrap .CodeMirror-scroll {
+  overflow-x: hidden;
+}
+
+.CodeMirror-measure {
+  position: absolute;
+  width: 100%;
+  height: 0;
+  overflow: hidden;
+  visibility: hidden;
+}
+.CodeMirror-measure pre { position: static; }
+
+.CodeMirror div.CodeMirror-cursor {
+  position: absolute;
+  border-right: none;
+  width: 0;
+}
+
+div.CodeMirror-cursors {
+  visibility: hidden;
+  position: relative;
+  z-index: 3;
+}
+.CodeMirror-focused div.CodeMirror-cursors {
+  visibility: visible;
+}
+
+.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
+.CodeMirror-crosshair { cursor: crosshair; }
+
+.cm-searching {
+  background: #ffa;
+  background: rgba(255, 255, 0, .4);
+}
+
+/* IE7 hack to prevent it from returning funny offsetTops on the spans */
+.CodeMirror span { *vertical-align: text-bottom; }
+
+/* Used to force a border model for a node */
+.cm-force-border { padding-right: .1px; }
+
+@media print {
+  /* Hide the cursor when printing */
+  .CodeMirror div.CodeMirror-cursors {
+    visibility: hidden;
+  }
+}
+
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext { background: none; }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.css
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.css b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.css
new file mode 100644
index 0000000..924e638
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.css
@@ -0,0 +1,38 @@
+.CodeMirror-hints {
+  position: absolute;
+  z-index: 10;
+  overflow: hidden;
+  list-style: none;
+
+  margin: 0;
+  padding: 2px;
+
+  -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+  -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+  box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+  border-radius: 3px;
+  border: 1px solid silver;
+
+  background: white;
+  font-size: 90%;
+  font-family: monospace;
+
+  max-height: 20em;
+  overflow-y: auto;
+}
+
+.CodeMirror-hint {
+  margin: 0;
+  padding: 0 4px;
+  border-radius: 2px;
+  max-width: 19em;
+  overflow: hidden;
+  white-space: pre;
+  color: black;
+  cursor: pointer;
+}
+
+li.CodeMirror-hint-active {
+  background: #08f;
+  color: white;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.js
new file mode 100644
index 0000000..27b770b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/show-hint.js
@@ -0,0 +1,389 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  var HINT_ELEMENT_CLASS        = "CodeMirror-hint";
+  var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
+
+  // This is the old interface, kept around for now to stay
+  // backwards-compatible.
+  CodeMirror.showHint = function(cm, getHints, options) {
+    if (!getHints) return cm.showHint(options);
+    if (options && options.async) getHints.async = true;
+    var newOpts = {hint: getHints};
+    if (options) for (var prop in options) newOpts[prop] = options[prop];
+    return cm.showHint(newOpts);
+  };
+
+  CodeMirror.defineExtension("showHint", function(options) {
+    // We want a single cursor position.
+    if (this.listSelections().length > 1 || this.somethingSelected()) return;
+
+    if (this.state.completionActive) this.state.completionActive.close();
+    var completion = this.state.completionActive = new Completion(this, options);
+    var getHints = completion.options.hint;
+    if (!getHints) return;
+
+    CodeMirror.signal(this, "startCompletion", this);
+    if (getHints.async)
+      getHints(this, function(hints) { completion.showHints(hints); }, completion.options);
+    else
+      return completion.showHints(getHints(this, completion.options));
+  });
+
+  function Completion(cm, options) {
+    this.cm = cm;
+    this.options = this.buildOptions(options);
+    this.widget = this.onClose = null;
+  }
+
+  Completion.prototype = {
+    close: function() {
+      if (!this.active()) return;
+      this.cm.state.completionActive = null;
+
+      if (this.widget) this.widget.close();
+      if (this.onClose) this.onClose();
+      CodeMirror.signal(this.cm, "endCompletion", this.cm);
+    },
+
+    active: function() {
+      return this.cm.state.completionActive == this;
+    },
+
+    pick: function(data, i) {
+      var completion = data.list[i];
+      if (completion.hint) completion.hint(this.cm, data, completion);
+      else this.cm.replaceRange(getText(completion), completion.from || data.from,
+                                completion.to || data.to, "complete");
+      CodeMirror.signal(data, "pick", completion);
+      this.close();
+    },
+
+    showHints: function(data) {
+      if (!data || !data.list.length || !this.active()) return this.close();
+
+      if (this.options.completeSingle && data.list.length == 1)
+        this.pick(data, 0);
+      else
+        this.showWidget(data);
+    },
+
+    showWidget: function(data) {
+      this.widget = new Widget(this, data);
+      CodeMirror.signal(data, "shown");
+
+      var debounce = 0, completion = this, finished;
+      var closeOn = this.options.closeCharacters;
+      var startPos = this.cm.getCursor(), startLen = this.cm.getLine(startPos.line).length;
+
+      var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
+        return setTimeout(fn, 1000/60);
+      };
+      var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
+
+      function done() {
+        if (finished) return;
+        finished = true;
+        completion.close();
+        completion.cm.off("cursorActivity", activity);
+        if (data) CodeMirror.signal(data, "close");
+      }
+
+      function update() {
+        if (finished) return;
+        CodeMirror.signal(data, "update");
+        var getHints = completion.options.hint;
+        if (getHints.async)
+          getHints(completion.cm, finishUpdate, completion.options);
+        else
+          finishUpdate(getHints(completion.cm, completion.options));
+      }
+      function finishUpdate(data_) {
+        data = data_;
+        if (finished) return;
+        if (!data || !data.list.length) return done();
+        if (completion.widget) completion.widget.close();
+        completion.widget = new Widget(completion, data);
+      }
+
+      function clearDebounce() {
+        if (debounce) {
+          cancelAnimationFrame(debounce);
+          debounce = 0;
+        }
+      }
+
+      function activity() {
+        clearDebounce();
+        var pos = completion.cm.getCursor(), line = completion.cm.getLine(pos.line);
+        if (pos.line != startPos.line || line.length - pos.ch != startLen - startPos.ch ||
+            pos.ch < startPos.ch || completion.cm.somethingSelected() ||
+            (pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) {
+          completion.close();
+        } else {
+          debounce = requestAnimationFrame(update);
+          if (completion.widget) completion.widget.close();
+        }
+      }
+      this.cm.on("cursorActivity", activity);
+      this.onClose = done;
+    },
+
+    buildOptions: function(options) {
+      var editor = this.cm.options.hintOptions;
+      var out = {};
+      for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
+      if (editor) for (var prop in editor)
+        if (editor[prop] !== undefined) out[prop] = editor[prop];
+      if (options) for (var prop in options)
+        if (options[prop] !== undefined) out[prop] = options[prop];
+      return out;
+    }
+  };
+
+  function getText(completion) {
+    if (typeof completion == "string") return completion;
+    else return completion.text;
+  }
+
+  function buildKeyMap(completion, handle) {
+    var baseMap = {
+      Up: function() {handle.moveFocus(-1);},
+      Down: function() {handle.moveFocus(1);},
+      PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
+      PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
+      Home: function() {handle.setFocus(0);},
+      End: function() {handle.setFocus(handle.length - 1);},
+      Enter: handle.pick,
+      Tab: handle.pick,
+      Esc: handle.close
+    };
+    var custom = completion.options.customKeys;
+    var ourMap = custom ? {} : baseMap;
+    function addBinding(key, val) {
+      var bound;
+      if (typeof val != "string")
+        bound = function(cm) { return val(cm, handle); };
+      // This mechanism is deprecated
+      else if (baseMap.hasOwnProperty(val))
+        bound = baseMap[val];
+      else
+        bound = val;
+      ourMap[key] = bound;
+    }
+    if (custom)
+      for (var key in custom) if (custom.hasOwnProperty(key))
+        addBinding(key, custom[key]);
+    var extra = completion.options.extraKeys;
+    if (extra)
+      for (var key in extra) if (extra.hasOwnProperty(key))
+        addBinding(key, extra[key]);
+    return ourMap;
+  }
+
+  function getHintElement(hintsElement, el) {
+    while (el && el != hintsElement) {
+      if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
+      el = el.parentNode;
+    }
+  }
+
+  function Widget(completion, data) {
+    this.completion = completion;
+    this.data = data;
+    var widget = this, cm = completion.cm;
+
+    var hints = this.hints = document.createElement("ul");
+    hints.className = "CodeMirror-hints";
+    this.selectedHint = data.selectedHint || 0;
+
+    var completions = data.list;
+    for (var i = 0; i < completions.length; ++i) {
+      var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
+      var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
+      if (cur.className != null) className = cur.className + " " + className;
+      elt.className = className;
+      if (cur.render) cur.render(elt, data, cur);
+      else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
+      elt.hintId = i;
+    }
+
+    var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
+    var left = pos.left, top = pos.bottom, below = true;
+    hints.style.left = left + "px";
+    hints.style.top = top + "px";
+    // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
+    var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
+    var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
+    (completion.options.container || document.body).appendChild(hints);
+    var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
+    if (overlapY > 0) {
+      var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
+      if (curTop - height > 0) { // Fits above cursor
+        hints.style.top = (top = pos.top - height) + "px";
+        below = false;
+      } else if (height > winH) {
+        hints.style.height = (winH - 5) + "px";
+        hints.style.top = (top = pos.bottom - box.top) + "px";
+        var cursor = cm.getCursor();
+        if (data.from.ch != cursor.ch) {
+          pos = cm.cursorCoords(cursor);
+          hints.style.left = (left = pos.left) + "px";
+          box = hints.getBoundingClientRect();
+        }
+      }
+    }
+    var overlapX = box.left - winW;
+    if (overlapX > 0) {
+      if (box.right - box.left > winW) {
+        hints.style.width = (winW - 5) + "px";
+        overlapX -= (box.right - box.left) - winW;
+      }
+      hints.style.left = (left = pos.left - overlapX) + "px";
+    }
+
+    cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
+      moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
+      setFocus: function(n) { widget.changeActive(n); },
+      menuSize: function() { return widget.screenAmount(); },
+      length: completions.length,
+      close: function() { completion.close(); },
+      pick: function() { widget.pick(); },
+      data: data
+    }));
+
+    if (completion.options.closeOnUnfocus) {
+      var closingOnBlur;
+      cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
+      cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
+    }
+
+    var startScroll = cm.getScrollInfo();
+    cm.on("scroll", this.onScroll = function() {
+      var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
+      var newTop = top + startScroll.top - curScroll.top;
+      var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
+      if (!below) point += hints.offsetHeight;
+      if (point <= editor.top || point >= editor.bottom) return completion.close();
+      hints.style.top = newTop + "px";
+      hints.style.left = (left + startScroll.left - curScroll.left) + "px";
+    });
+
+    CodeMirror.on(hints, "dblclick", function(e) {
+      var t = getHintElement(hints, e.target || e.srcElement);
+      if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
+    });
+
+    CodeMirror.on(hints, "click", function(e) {
+      var t = getHintElement(hints, e.target || e.srcElement);
+      if (t && t.hintId != null) {
+        widget.changeActive(t.hintId);
+        if (completion.options.completeOnSingleClick) widget.pick();
+      }
+    });
+
+    CodeMirror.on(hints, "mousedown", function() {
+      setTimeout(function(){cm.focus();}, 20);
+    });
+
+    CodeMirror.signal(data, "select", completions[0], hints.firstChild);
+    return true;
+  }
+
+  Widget.prototype = {
+    close: function() {
+      if (this.completion.widget != this) return;
+      this.completion.widget = null;
+      this.hints.parentNode.removeChild(this.hints);
+      this.completion.cm.removeKeyMap(this.keyMap);
+
+      var cm = this.completion.cm;
+      if (this.completion.options.closeOnUnfocus) {
+        cm.off("blur", this.onBlur);
+        cm.off("focus", this.onFocus);
+      }
+      cm.off("scroll", this.onScroll);
+    },
+
+    pick: function() {
+      this.completion.pick(this.data, this.selectedHint);
+    },
+
+    changeActive: function(i, avoidWrap) {
+      if (i >= this.data.list.length)
+        i = avoidWrap ? this.data.list.length - 1 : 0;
+      else if (i < 0)
+        i = avoidWrap ? 0  : this.data.list.length - 1;
+      if (this.selectedHint == i) return;
+      var node = this.hints.childNodes[this.selectedHint];
+      node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
+      node = this.hints.childNodes[this.selectedHint = i];
+      node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
+      if (node.offsetTop < this.hints.scrollTop)
+        this.hints.scrollTop = node.offsetTop - 3;
+      else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
+        this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
+      CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
+    },
+
+    screenAmount: function() {
+      return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
+    }
+  };
+
+  CodeMirror.registerHelper("hint", "auto", function(cm, options) {
+    var helpers = cm.getHelpers(cm.getCursor(), "hint"), words;
+    if (helpers.length) {
+      for (var i = 0; i < helpers.length; i++) {
+        var cur = helpers[i](cm, options);
+        if (cur && cur.list.length) return cur;
+      }
+    } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
+      if (words) return CodeMirror.hint.fromList(cm, {words: words});
+    } else if (CodeMirror.hint.anyword) {
+      return CodeMirror.hint.anyword(cm, options);
+    }
+  });
+
+  CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
+    var cur = cm.getCursor(), token = cm.getTokenAt(cur);
+    var found = [];
+    for (var i = 0; i < options.words.length; i++) {
+      var word = options.words[i];
+      if (word.slice(0, token.string.length) == token.string)
+        found.push(word);
+    }
+
+    if (found.length) return {
+      list: found,
+      from: CodeMirror.Pos(cur.line, token.start),
+            to: CodeMirror.Pos(cur.line, token.end)
+    };
+  });
+
+  CodeMirror.commands.autocomplete = CodeMirror.showHint;
+
+  var defaultOptions = {
+    hint: CodeMirror.hint.auto,
+    completeSingle: true,
+    alignWithWord: true,
+    closeCharacters: /[\s()\[\]{};:>,]/,
+    closeOnUnfocus: true,
+    completeOnSingleClick: false,
+    container: null,
+    customKeys: null,
+    extraKeys: null
+  };
+
+  CodeMirror.defineOption("hintOptions", null);
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/sql-hint.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/sql-hint.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/sql-hint.js
new file mode 100644
index 0000000..522f9e8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/codemirror/sql-hint.js
@@ -0,0 +1,192 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  var tables;
+  var defaultTable;
+  var keywords;
+  var CONS = {
+    QUERY_DIV: ";",
+    ALIAS_KEYWORD: "AS"
+  };
+  var Pos = CodeMirror.Pos;
+
+  function getKeywords(editor) {
+    var mode = editor.doc.modeOption;
+    if (mode === "sql") mode = "text/x-sql";
+    return CodeMirror.resolveMode(mode).keywords;
+  }
+
+  function match(string, word) {
+    var len = string.length;
+    var sub = word.substr(0, len);
+    return string.toUpperCase() === sub.toUpperCase();
+  }
+
+  function addMatches(result, search, wordlist, formatter) {
+    for (var word in wordlist) {
+      if (!wordlist.hasOwnProperty(word)) continue;
+      if (Array.isArray(wordlist)) {
+        word = wordlist[word];
+      }
+      if (match(search, word)) {
+        result.push(formatter(word));
+      }
+    }
+  }
+
+  function nameCompletion(result, editor) {
+    var cur = editor.getCursor();
+    var token = editor.getTokenAt(cur);
+    var useBacktick = (token.string.charAt(0) == "`");
+    var string = token.string.substr(1);
+    var prevToken = editor.getTokenAt(Pos(cur.line, token.start));
+    if (token.string.charAt(0) == "." || prevToken.string == "."){
+      //Suggest colunm names
+      prevToken = prevToken.string == "." ? editor.getTokenAt(Pos(cur.line, token.start - 1)) : prevToken;
+      var table = prevToken.string;
+      //Check if backtick is used in table name. If yes, use it for columns too.
+      var useBacktickTable = false;
+      if (table.match(/`/g)) {
+        useBacktickTable = true;
+        table = table.replace(/`/g, "");
+      }
+      //Check if table is available. If not, find table by Alias
+      if (!tables.hasOwnProperty(table))
+        table = findTableByAlias(table, editor);
+      var columns = tables[table];
+      if (!columns) return;
+
+      if (useBacktick) {
+        addMatches(result, string, columns, function(w) {return "`" + w + "`";});
+      }
+      else if(useBacktickTable) {
+        addMatches(result, string, columns, function(w) {return ".`" + w + "`";});
+      }
+      else {
+        addMatches(result, string, columns, function(w) {return "." + w;});
+      }
+    }
+    else {
+      //Suggest table names or colums in defaultTable
+      while (token.start && string.charAt(0) == ".") {
+        token = editor.getTokenAt(Pos(cur.line, token.start - 1));
+        string = token.string + string;
+      }
+      if (useBacktick) {
+        addMatches(result, string, tables, function(w) {return "`" + w + "`";});
+        addMatches(result, string, defaultTable, function(w) {return "`" + w + "`";});
+      }
+      else {
+        addMatches(result, string, tables, function(w) {return w;});
+        addMatches(result, string, defaultTable, function(w) {return w;});
+      }
+    }
+  }
+
+  function eachWord(lineText, f) {
+    if (!lineText) return;
+    var excepted = /[,;]/g;
+    var words = lineText.split(" ");
+    for (var i = 0; i < words.length; i++) {
+      f(words[i]?words[i].replace(excepted, '') : '');
+    }
+  }
+
+  function convertCurToNumber(cur) {
+    // max characters of a line is 999,999.
+    return cur.line + cur.ch / Math.pow(10, 6);
+  }
+
+  function convertNumberToCur(num) {
+    return Pos(Math.floor(num), +num.toString().split('.').pop());
+  }
+
+  function findTableByAlias(alias, editor) {
+    var doc = editor.doc;
+    var fullQuery = doc.getValue();
+    var aliasUpperCase = alias.toUpperCase();
+    var previousWord = "";
+    var table = "";
+    var separator = [];
+    var validRange = {
+      start: Pos(0, 0),
+      end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length)
+    };
+
+    //add separator
+    var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV);
+    while(indexOfSeparator != -1) {
+      separator.push(doc.posFromIndex(indexOfSeparator));
+      indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1);
+    }
+    separator.unshift(Pos(0, 0));
+    separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));
+
+    //find valid range
+    var prevItem = 0;
+    var current = convertCurToNumber(editor.getCursor());
+    for (var i=0; i< separator.length; i++) {
+      var _v = convertCurToNumber(separator[i]);
+      if (current > prevItem && current <= _v) {
+        validRange = { start: convertNumberToCur(prevItem), end: convertNumberToCur(_v) };
+        break;
+      }
+      prevItem = _v;
+    }
+
+    var query = doc.getRange(validRange.start, validRange.end, false);
+
+    for (var i = 0; i < query.length; i++) {
+      var lineText = query[i];
+      eachWord(lineText, function(word) {
+        var wordUpperCase = word.toUpperCase();
+        if (wordUpperCase === aliasUpperCase && tables.hasOwnProperty(previousWord)) {
+            table = previousWord;
+        }
+        if (wordUpperCase !== CONS.ALIAS_KEYWORD) {
+          previousWord = word;
+        }
+      });
+      if (table) break;
+    }
+    return table;
+  }
+
+  CodeMirror.registerHelper("hint", "sql", function(editor, options) {
+    tables = (options && options.tables) || {};
+    var defaultTableName = options && options.defaultTable;
+    defaultTable = (defaultTableName && tables[defaultTableName] || []);
+    keywords = keywords || getKeywords(editor);
+
+    var cur = editor.getCursor();
+    var result = [];
+    var token = editor.getTokenAt(cur), start, end, search;
+    if (token.string.match(/^[.`\w@]\w*$/)) {
+      search = token.string;
+      start = token.start;
+      end = token.end;
+    } else {
+      start = end = cur.ch;
+      search = "";
+    }
+    if (search.charAt(0) == "." || search.charAt(0) == "`") {
+      nameCompletion(result, editor);
+    } else {
+      addMatches(result, search, tables, function(w) {return w;});
+      addMatches(result, search, defaultTable, function(w) {return w;});
+      addMatches(result, search, keywords, function(w) {return w.toUpperCase();});
+    }
+
+    return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
+  });
+});


[34/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services


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

Branch: refs/heads/branch-yarnapps-dev
Commit: b88db3cc005dd5b98a4569533db6573518a94a82
Parents: 270c23f
Author: Jayush Luniya <jl...@hortonworks.com>
Authored: Mon Jun 27 16:36:09 2016 -0700
Committer: Jayush Luniya <jl...@hortonworks.com>
Committed: Mon Jun 27 16:36:09 2016 -0700

----------------------------------------------------------------------
 .../ambariViews/CreateViewInstanceCtrl.js       |     19 +-
 .../controllers/ambariViews/ViewsEditCtrl.js    |     28 +-
 .../remoteClusters/RemoteClustersEditCtrl.js    |     13 +-
 .../admin-web/app/scripts/services/Cluster.js   |      2 +-
 .../app/scripts/services/RemoteCluster.js       |      2 +-
 .../ui/admin-web/app/scripts/services/View.js   |      4 +-
 .../admin-web/app/views/ambariViews/create.html |      4 +-
 .../admin-web/app/views/ambariViews/edit.html   |      4 +-
 .../remoteClusters/editRemoteClusterPage.html   |      2 +-
 .../unit/controllers/CreateViewInstanceCtrl.js  |      4 +-
 ambari-agent/pom.xml                            |      2 +-
 ambari-client/python-client/pom.xml             |      2 +-
 ambari-logsearch/pom.xml                        |      2 +-
 ambari-server/pom.xml                           |      3 +-
 ambari-server/src/main/assemblies/server.xml    |      5 +
 .../eventdb/webservice/WorkflowJsonService.java |      1 -
 .../ambari/server/ClusterNotFoundException.java |      4 +
 .../ServiceComponentNotFoundException.java      |      4 +-
 .../server/ServiceGroupNotFoundException.java   |     29 +
 .../ambari/server/agent/HeartbeatMonitor.java   |      8 +-
 .../ambari/server/agent/HeartbeatProcessor.java |      2 +-
 .../resources/ClusterResourceDefinition.java    |      1 +
 .../resources/ResourceInstanceFactoryImpl.java  |      4 +
 .../ServiceGroupResourceDefinition.java         |     54 +
 .../server/api/rest/BootStrapResource.java      |      1 -
 .../ambari/server/api/rest/HealthCheck.java     |      1 -
 .../api/rest/KdcServerReachabilityCheck.java    |      1 -
 .../api/services/AbstractVersionService.java    |    352 +
 .../server/api/services/ActionService.java      |      6 +-
 .../api/services/ActiveWidgetLayoutService.java |      4 +-
 .../api/services/AlertDefinitionService.java    |      6 +-
 .../server/api/services/AlertGroupService.java  |      4 +-
 .../api/services/AlertHistoryService.java       |      4 +-
 .../server/api/services/AlertNoticeService.java |      4 +-
 .../server/api/services/AlertService.java       |      4 +-
 .../server/api/services/AlertTargetService.java |      6 +-
 .../server/api/services/AmbariMetaInfo.java     |     13 +-
 .../api/services/AmbariPrivilegeService.java    |      5 +-
 .../ambari/server/api/services/BaseService.java |     17 +
 .../server/api/services/BlueprintService.java   |      6 +-
 .../ClusterKerberosDescriptorService.java       |      4 +-
 .../api/services/ClusterPrivilegeService.java   |      4 +-
 .../server/api/services/ClusterService.java     |     71 +-
 .../services/ClusterStackVersionService.java    |      6 +-
 .../CompatibleRepositoryVersionService.java     |      6 +-
 .../server/api/services/ComponentService.java   |      4 +-
 .../server/api/services/ConfigGroupService.java |      4 +-
 .../api/services/ConfigurationService.java      |      6 +-
 .../server/api/services/CredentialService.java  |      4 +-
 .../ambari/server/api/services/FeedService.java |      8 +-
 .../api/services/GroupPrivilegeService.java     |      4 +-
 .../server/api/services/GroupService.java       |     10 +-
 .../api/services/HostComponentService.java      |      6 +-
 .../services/HostKerberosIdentityService.java   |      4 +-
 .../ambari/server/api/services/HostService.java |     18 +-
 .../api/services/HostStackVersionService.java   |      6 +-
 .../server/api/services/InstanceService.java    |      8 +-
 .../ambari/server/api/services/JobService.java  |      6 +-
 .../api/services/KerberosDescriptorService.java |      6 +-
 .../ambari/server/api/services/KeyService.java  |      1 -
 .../api/services/LdapSyncEventService.java      |      6 +-
 .../server/api/services/LoggingService.java     |      9 +-
 .../server/api/services/LogoutService.java      |      1 -
 .../server/api/services/MemberService.java      |      4 +-
 .../api/services/OperatingSystemService.java    |      6 +-
 .../server/api/services/PermissionService.java  |      8 +-
 .../api/services/PersistKeyValueService.java    |      1 -
 .../api/services/PreUpgradeCheckService.java    |      4 +-
 .../server/api/services/PrivilegeService.java   |      5 +
 .../api/services/RecommendationService.java     |     71 -
 .../api/services/RemoteClustersService.java     |      6 +-
 .../server/api/services/RepositoryService.java  |      4 +-
 .../api/services/RepositoryVersionService.java  |      6 +-
 .../api/services/RequestScheduleService.java    |      4 +-
 .../server/api/services/RequestService.java     |     12 +-
 .../api/services/RoleAuthorizationService.java  |      9 +-
 .../server/api/services/RootServiceService.java |      8 +-
 .../services/ServiceConfigVersionService.java   |      4 +-
 .../api/services/ServiceGroupService.java       |    192 +
 .../server/api/services/ServiceService.java     |     14 +-
 .../server/api/services/SettingService.java     |      6 +-
 .../server/api/services/StacksService.java      |     79 +-
 .../server/api/services/StageService.java       |      6 +-
 .../api/services/TargetClusterService.java      |      6 +-
 .../server/api/services/TaskAttemptService.java |      4 +-
 .../ambari/server/api/services/TaskService.java |      4 +-
 .../api/services/UpgradeGroupService.java       |      6 +-
 .../server/api/services/UpgradeItemService.java |      6 +-
 .../server/api/services/UpgradeService.java     |      6 +-
 .../api/services/UpgradeSummaryService.java     |      4 +-
 .../api/services/UserAuthorizationService.java  |      4 +-
 .../api/services/UserPrivilegeService.java      |      4 +-
 .../ambari/server/api/services/UserService.java |     12 +-
 .../ambari/server/api/services/V1Service.java   |     44 +
 .../ambari/server/api/services/V2Service.java   |     44 +
 .../server/api/services/ValidationService.java  |     70 -
 .../api/services/VersionDefinitionService.java  |      8 +-
 .../api/services/ViewDataMigrationService.java  |      4 +-
 .../ViewExternalSubResourceService.java         |      4 +-
 .../api/services/ViewInstanceService.java       |      8 +-
 .../api/services/ViewPermissionService.java     |      4 +-
 .../api/services/ViewPrivilegeService.java      |      4 +-
 .../ambari/server/api/services/ViewService.java |      8 +-
 .../api/services/ViewSubResourceService.java    |      4 +-
 .../server/api/services/ViewUrlsService.java    |      6 +-
 .../server/api/services/ViewVersionService.java |      8 +-
 .../api/services/WidgetLayoutService.java       |      4 +-
 .../server/api/services/WidgetService.java      |      4 +-
 .../server/api/services/WorkflowService.java    |      6 +-
 .../stackadvisor/StackAdvisorHelper.java        |     11 +-
 .../ComponentLayoutRecommendationCommand.java   |      5 +-
 .../ComponentLayoutValidationCommand.java       |      5 +-
 ...rationDependenciesRecommendationCommand.java |      5 +-
 .../ConfigurationRecommendationCommand.java     |      6 +-
 .../ConfigurationValidationCommand.java         |      5 +-
 .../commands/StackAdvisorCommand.java           |      6 +-
 .../ambari/server/api/util/ApiVersion.java      |     31 +
 .../server/configuration/Configuration.java     |      7 +
 .../AmbariCustomCommandExecutionHelper.java     |      2 +-
 .../controller/AmbariManagementController.java  |     32 +
 .../AmbariManagementControllerImpl.java         |    376 +-
 .../ambari/server/controller/AmbariServer.java  |      7 +-
 .../server/controller/ControllerModule.java     |     11 +
 .../controller/ResourceProviderFactory.java     |      5 +
 .../ServiceComponentHostResponse.java           |     50 +-
 .../controller/ServiceComponentRequest.java     |     30 +-
 .../controller/ServiceComponentResponse.java    |     21 +
 .../server/controller/ServiceGroupRequest.java  |    152 +
 .../server/controller/ServiceGroupResponse.java |    239 +
 .../server/controller/ServiceRequest.java       |     36 +-
 .../server/controller/ServiceResponse.java      |     34 +-
 .../AbstractControllerResourceProvider.java     |      2 +
 .../internal/ComponentResourceProvider.java     |    128 +-
 .../internal/DashHttpPropertyRequest.java       |     46 +
 .../internal/HostComponentResourceProvider.java |      8 +
 .../QuickLinkArtifactResourceProvider.java      |     20 +-
 .../internal/RemoteClusterResourceProvider.java |     35 +-
 .../internal/ServiceGroupResourceProvider.java  |    759 +
 .../internal/ServiceResourceProvider.java       |     40 +-
 .../internal/ViewInstanceResourceProvider.java  |      2 +-
 .../servicegroup/cache/ServiceGroupCache.java   |    124 +
 .../cache/ServiceGroupCacheEntryFactory.java    |    102 +
 .../cache/ServiceGroupCacheKey.java             |     55 +
 .../cache/ServiceGroupCacheProvider.java        |    114 +
 .../cache/ServiceGroupCacheValue.java           |    135 +
 .../ambari/server/controller/spi/Resource.java  |      2 +
 .../controller/utilities/DatabaseChecker.java   |     24 +-
 .../ambari/server/events/AmbariEvent.java       |     10 +
 .../events/ServiceComponentInstalledEvent.java  |      4 +-
 .../ServiceComponentUninstalledEvent.java       |      5 +-
 .../ambari/server/events/ServiceEvent.java      |     30 +-
 .../ambari/server/events/ServiceGroupEvent.java |     49 +
 .../events/ServiceGroupInstalledEvent.java      |     46 +
 .../server/events/ServiceGroupRemovedEvent.java |     46 +
 .../server/events/ServiceInstalledEvent.java    |      4 +-
 .../server/events/ServiceRemovedEvent.java      |      4 +-
 .../server/orm/dao/ClusterServiceGroupDAO.java  |     93 +
 .../server/orm/dao/RemoteAmbariClusterDAO.java  |     13 +
 .../orm/entities/ClusterConfigEntity.java       |     11 +
 .../server/orm/entities/ClusterEntity.java      |     11 +
 .../orm/entities/ClusterServiceEntity.java      |     22 +
 .../orm/entities/ClusterServiceGroupEntity.java |    153 +
 .../entities/ClusterServiceGroupEntityPK.java   |     71 +
 .../orm/entities/RemoteAmbariClusterEntity.java |      8 +-
 .../ServiceComponentDesiredStateEntity.java     |     10 +
 .../server/orm/entities/ViewInstanceEntity.java |      8 +-
 .../servicegroup/ServiceGroupServerAction.java  |     91 +
 .../YarnServiceGroupServerAction.java           |    171 +
 .../org/apache/ambari/server/state/Cluster.java |     42 +-
 .../apache/ambari/server/state/Clusters.java    |      8 +
 .../org/apache/ambari/server/state/Config.java  |      5 +
 .../apache/ambari/server/state/ConfigImpl.java  |     16 +
 .../org/apache/ambari/server/state/Service.java |      4 +
 .../ambari/server/state/ServiceComponent.java   |      8 +
 .../server/state/ServiceComponentHost.java      |     12 +
 .../server/state/ServiceComponentImpl.java      |     79 +-
 .../ambari/server/state/ServiceFactory.java     |      6 +-
 .../ambari/server/state/ServiceGroup.java       |     79 +
 .../server/state/ServiceGroupFactory.java       |     35 +
 .../ambari/server/state/ServiceGroupImpl.java   |    378 +
 .../apache/ambari/server/state/ServiceImpl.java |     43 +-
 .../apache/ambari/server/state/StackInfo.java   |     34 +-
 .../server/state/cluster/ClusterImpl.java       |    236 +-
 .../server/state/cluster/ClustersImpl.java      |     16 +
 .../state/configgroup/ConfigGroupImpl.java      |      1 +
 .../svccomphost/ServiceComponentHostImpl.java   |     17 +-
 .../ambari/server/topology/AmbariContext.java   |      4 +-
 .../server/upgrade/UpgradeCatalog150.java       |      7 +-
 .../server/upgrade/UpgradeCatalog240.java       |     55 +-
 .../apache/ambari/server/utils/MapUtils.java    |     45 +
 .../view/RemoteAmbariClusterRegistry.java       |     12 +-
 .../ambari/server/view/ViewContextImpl.java     |      2 +-
 .../apache/ambari/server/view/ViewRegistry.java |     18 +-
 .../main/resources/Ambari-DDL-Derby-CREATE.sql  |     16 +-
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |     17 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |     17 +-
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |     17 +-
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |     18 +-
 .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql |     17 +-
 .../resources/Ambari-DDL-SQLServer-CREATE.sql   |     17 +-
 .../src/main/resources/META-INF/persistence.xml |      1 +
 ambari-server/src/main/resources/ambari.repo    |      8 +
 ambari-server/src/main/resources/app.js         | 219702 ++++++++++++++++
 .../src/main/resources/componentsMap.dat        |     12 +
 .../src/main/resources/key_properties.json      |      5 +
 .../src/main/resources/properties.json          |     23 +-
 .../stacks/HDP/2.4/services/CFMON/metainfo.xml  |     43 +
 .../stacks/HDP/2.4/services/NIFI/metainfo.xml   |     37 +
 .../server/agent/HeartbeatProcessorTest.java    |     24 +-
 .../server/agent/TestHeartbeatHandler.java      |     22 +-
 .../server/agent/TestHeartbeatMonitor.java      |     10 +-
 .../server/api/services/ActionServiceTest.java  |      2 +
 .../services/ActiveWidgetLayoutServiceTest.java |      3 +-
 .../server/api/services/AmbariMetaInfoTest.java |      2 +-
 .../api/services/BlueprintServiceTest.java      |      4 +-
 .../ClusterKerberosDescriptorServiceTest.java   |      3 +-
 .../services/ClusterPrivilegeServiceTest.java   |      3 +-
 .../server/api/services/ClusterServiceTest.java |      3 +-
 .../ClusterStackVersionServiceTest.java         |      3 +-
 .../api/services/ComponentServiceTest.java      |      3 +-
 .../api/services/ConfigGroupServiceTest.java    |      3 +-
 .../api/services/ConfigurationServiceTest.java  |      3 +-
 .../api/services/CredentialServiceTest.java     |      3 +-
 .../server/api/services/FeedServiceTest.java    |      2 +
 .../api/services/GroupPrivilegeServiceTest.java |      3 +-
 .../server/api/services/GroupServiceTest.java   |      5 +
 .../api/services/HostComponentServiceTest.java  |      3 +-
 .../HostKerberosIdentityServiceTest.java        |      3 +-
 .../server/api/services/HostServiceTest.java    |      3 +-
 .../services/HostStackVersionServiceTest.java   |      3 +-
 .../api/services/InstanceServiceTest.java       |      3 +-
 .../server/api/services/JobServiceTest.java     |      3 +-
 .../api/services/LdapSyncEventServiceTest.java  |      3 +-
 .../server/api/services/MemberServiceTest.java  |      3 +-
 .../api/services/PermissionServiceTest.java     |      2 +
 .../services/PreUpgradeCheckServiceTest.java    |      3 +-
 .../api/services/PrivilegeServiceTest.java      |      2 +
 .../api/services/RecommendationServiceTest.java |      7 +-
 .../api/services/RepositoryServiceTest.java     |      3 +-
 .../services/RoleAuthorizationServiceTest.java  |      2 +
 .../api/services/RootServiceServiceTest.java    |      2 +
 .../server/api/services/ServiceServiceTest.java |      5 +-
 .../server/api/services/SettingServiceTest.java |      2 +
 .../server/api/services/StacksServiceTest.java  |      2 +
 .../api/services/TargetClusterServiceTest.java  |      2 +
 .../api/services/TaskAttemptServiceTest.java    |      3 +-
 .../api/services/UpgradeItemServiceTest.java    |      3 +-
 .../services/UserAuthorizationServiceTest.java  |      5 +-
 .../api/services/UserPrivilegeServiceTest.java  |      5 +-
 .../server/api/services/UserServiceTest.java    |      5 +
 .../api/services/ValidationServiceTest.java     |      7 +-
 .../services/ViewDataMigrationServiceTest.java  |      3 +-
 .../ViewExternalSubResourceServiceTest.java     |      3 +-
 .../api/services/ViewPermissionServiceTest.java |      3 +-
 .../services/ViewSubResourceServiceTest.java    |      7 +-
 .../api/services/WorkflowServiceTest.java       |      3 +-
 .../ConfigurationRecommendationCommandTest.java |      3 +-
 .../commands/StackAdvisorCommandTest.java       |      3 +-
 .../creator/ServiceEventCreatorTest.java        |      3 +
 .../configuration/RecoveryConfigHelperTest.java |     12 +-
 .../AmbariCustomCommandExecutionHelperTest.java |      2 +-
 .../AmbariManagementControllerImplTest.java     |      4 +-
 .../AmbariManagementControllerTest.java         |    288 +-
 .../BackgroundCustomCommandExecutionTest.java   |      2 +-
 ...hYarnCapacitySchedulerReleaseConfigTest.java |      2 +-
 .../internal/ComponentResourceProviderTest.java |     36 +-
 .../internal/JMXHostProviderTest.java           |      2 +-
 .../internal/ServiceResourceProviderTest.java   |      4 +-
 .../UpgradeResourceProviderHDP22Test.java       |      2 +-
 .../internal/UpgradeResourceProviderTest.java   |      4 +-
 .../UpgradeSummaryResourceProviderTest.java     |      2 +-
 .../UserPrivilegeResourceProviderTest.java      |      2 +-
 .../ViewInstanceResourceProviderTest.java       |      4 +-
 .../GeneralServiceCalculatedStateTest.java      |      2 +-
 .../apache/ambari/server/events/EventsTest.java |      2 +-
 .../HostVersionOutOfSyncListenerTest.java       |      6 +-
 .../apache/ambari/server/orm/OrmTestHelper.java |      4 +-
 .../authorization/AuthorizationHelperTest.java  |      2 +-
 .../ComponentVersionCheckActionTest.java        |      2 +-
 .../upgrades/ConfigureActionTest.java           |      2 +-
 .../upgrades/UpgradeActionTest.java             |      2 +-
 .../server/state/ServiceComponentTest.java      |      2 +-
 .../apache/ambari/server/state/ServiceTest.java |     18 +-
 .../ambari/server/state/UpgradeHelperTest.java  |     20 +-
 .../state/alerts/AlertEventPublisherTest.java   |      2 +-
 .../state/alerts/InitialAlertEventTest.java     |      2 +-
 .../state/cluster/ClusterDeadlockTest.java      |      2 +-
 .../server/state/cluster/ClusterImplTest.java   |      4 +-
 .../server/state/cluster/ClusterTest.java       |     44 +-
 .../state/cluster/ClustersDeadlockTest.java     |      2 +-
 .../server/state/cluster/ClustersTest.java      |      2 +-
 .../ConcurrentServiceConfigVersionTest.java     |      2 +-
 ...omponentHostConcurrentWriteDeadlockTest.java |      4 +-
 .../svccomphost/ServiceComponentHostTest.java   |      2 +-
 .../server/upgrade/UpgradeCatalog240Test.java   |     24 +-
 .../ambari/server/utils/StageUtilsTest.java     |      2 +-
 .../ambari/server/view/ViewRegistryTest.java    |      2 +-
 ambari-shell/ambari-python-shell/pom.xml        |      2 +-
 .../ambari/view/ViewInstanceDefinition.java     |      6 +-
 ambari-web/app/assets/img/accumulo-color.png    |    Bin 0 -> 9714 bytes
 .../app/assets/img/assemblies-background.png    |    Bin 0 -> 21801 bytes
 ambari-web/app/assets/img/assemblies-banner.jpg |    Bin 0 -> 94082 bytes
 ambari-web/app/assets/img/cfmon-color.png       |    Bin 0 -> 35895 bytes
 ambari-web/app/assets/img/falcon-color.png      |    Bin 0 -> 25897 bytes
 ambari-web/app/assets/img/hbase-color.png       |    Bin 0 -> 8741 bytes
 ambari-web/app/assets/img/jenkins-color.png     |    Bin 0 -> 26899 bytes
 ambari-web/app/assets/img/kafka-color.png       |    Bin 0 -> 13520 bytes
 ambari-web/app/assets/img/memcache-color.png    |    Bin 0 -> 9067 bytes
 ambari-web/app/assets/img/metron-color.png      |    Bin 0 -> 13917 bytes
 ambari-web/app/assets/img/nifi-color.png        |    Bin 0 -> 21756 bytes
 ambari-web/app/assets/img/solr-color.png        |    Bin 0 -> 23684 bytes
 ambari-web/app/assets/img/spark-color.png       |    Bin 0 -> 15013 bytes
 ambari-web/app/assets/img/sqoop-color.png       |    Bin 0 -> 16264 bytes
 ambari-web/app/assets/img/storm-color.png       |    Bin 0 -> 30380 bytes
 ambari-web/app/assets/img/zookeeper-color.png   |    Bin 0 -> 38773 bytes
 ambari-web/app/assets/licenses/NOTICE.txt       |      3 +
 ambari-web/app/assets/test/tests.js             |      6 +
 ambari-web/app/controllers.js                   |     11 +
 ambari-web/app/controllers/application.js       |      7 +-
 .../controllers/global/cluster_controller.js    |     15 +-
 .../global/errors_handler_controller.js         |      2 +-
 .../app/controllers/global/update_controller.js |     13 +-
 .../assemblies/assemblies_set_controller.js     |    150 +
 .../categories/category_controller.js           |     25 +
 .../main/assemblies/categories_controller.js    |     25 +
 .../collections/collection_controller.js        |     25 +
 .../main/assemblies/collections_controller.js   |     25 +
 .../service_groups/configs_controller.js        |     33 +
 .../service_groups/detailed_info_controller.js  |     38 +
 .../service_groups/service_group_controller.js  |     53 +
 .../service_groups/summary_controller.js        |     28 +
 .../assemblies/service_groups_controller.js     |     25 +
 .../controllers/main/assemblies_controller.js   |    233 +
 ambari-web/app/controllers/main/dashboard.js    |      8 +-
 ambari-web/app/controllers/main/service.js      |    136 +-
 .../controllers/main/service/info/configs.js    |      6 +-
 .../controllers/main/service/info/summary.js    |      2 +-
 .../service/widgets/create/wizard_controller.js |      2 +-
 ambari-web/app/mappers.js                       |      1 +
 .../app/mappers/components_state_mapper.js      |     15 +-
 ambari-web/app/mappers/service_group_mapper.js  |    122 +
 ambari-web/app/mappers/service_mapper.js        |     12 +-
 .../app/mappers/service_metrics_mapper.js       |     12 +-
 ambari-web/app/messages.js                      |     60 +-
 .../app/mixins/common/widgets/widget_section.js |      7 +-
 ambari-web/app/models.js                        |      4 +
 ambari-web/app/models/app_store/store_app.js    |    268 +
 .../app/models/app_store/store_category.js      |     37 +
 .../app/models/app_store/store_collection.js    |     31 +
 ambari-web/app/models/service.js                |     29 +-
 ambari-web/app/models/service_group.js          |    270 +
 ambari-web/app/router.js                        |      7 +
 ambari-web/app/routes/main.js                   |    216 +-
 ambari-web/app/styles/app_store.less            |    811 +
 ambari-web/app/styles/application.less          |     21 +
 ambari-web/app/templates/application.hbs        |      2 +-
 ambari-web/app/templates/common/collapsible.hbs |     21 +
 ambari-web/app/templates/main/assemblies.hbs    |    107 +
 .../main/assemblies/active_store_app.hbs        |     42 +
 .../app/templates/main/assemblies/apps_row.hbs  |     45 +
 .../main/assemblies/categories/category.hbs     |     32 +
 .../main/assemblies/collections/collection.hbs  |     30 +
 .../main/assemblies/deploy_store_app.hbs        |     25 +
 .../main/assemblies/deploy_store_app/config.hbs |     30 +
 .../deploy_store_app_footer.hbs                 |     44 +
 .../deploy_store_app_header.hbs                 |     26 +
 .../main/assemblies/service_groups/configs.hbs  |     27 +
 .../assemblies/service_groups/detailed_info.hbs |    114 +
 .../main/assemblies/service_groups/menu.hbs     |     25 +
 .../assemblies/service_groups/service_group.hbs |     38 +
 .../main/assemblies/service_groups/summary.hbs  |     66 +
 .../main/assemblies/store_app_block.hbs         |     41 +
 ambari-web/app/templates/main/dashboard.hbs     |     34 +-
 ambari-web/app/templates/main/service.hbs       |     18 +-
 .../main/service/all_services_actions.hbs       |     36 +-
 ambari-web/app/templates/main/service/item.hbs  |      2 +-
 ambari-web/app/utils/ajax/ajax.js               |     20 +
 ambari-web/app/utils/handlebars_helpers.js      |      9 +-
 ambari-web/app/utils/misc.js                    |      6 +-
 ambari-web/app/views.js                         |     19 +
 ambari-web/app/views/common/collapsible_view.js |     84 +
 .../app/views/common/helpers/nl2br_view.js      |     31 +
 .../main/assemblies/active_store_app_view.js    |     56 +
 .../app/views/main/assemblies/apps_row_view.js  |     89 +
 .../main/assemblies/categories/category_view.js |     25 +
 .../views/main/assemblies/categories_view.js    |     23 +
 .../assemblies/collections/collection_view.js   |     25 +
 .../views/main/assemblies/collections_view.js   |     23 +
 .../deploy_store_app/deploy_store_app_view.js   |     62 +
 .../assemblies/service_groups/configs_view.js   |     25 +
 .../service_groups/detailed_info_view.js        |     25 +
 .../main/assemblies/service_groups/menu_view.js |     50 +
 .../service_groups/service_group_view.js        |     25 +
 .../assemblies/service_groups/summary_view.js   |    186 +
 .../main/assemblies/service_groups_view.js      |     23 +
 .../main/assemblies/store_app_block_view.js     |     82 +
 ambari-web/app/views/main/assemblies_view.js    |     29 +
 ambari-web/app/views/main/dashboard.js          |      3 +
 ambari-web/app/views/main/menu.js               |     17 +-
 .../views/main/service/all_services_actions.js  |     29 +
 .../app/views/main/service/info/summary.js      |      4 +-
 ambari-web/app/views/main/service/item.js       |     15 +-
 ambari-web/app/views/main/service/menu.js       |     96 +-
 .../service/widgets/create/expression_view.js   |      2 +-
 ambari-web/config.coffee                        |      6 +-
 .../global/update_controller_test.js            |      2 +-
 .../assemblies_set_controller_test.js           |     35 +
 .../main/assemblies_controller_test.js          |     35 +
 .../test/controllers/main/service_test.js       |    159 +-
 ambari-web/test/models/service_group_test.js    |     47 +
 .../assemblies/active_store_app_view_test.js    |     29 +
 .../views/main/assemblies/apps_row_view_test.js |     39 +
 .../assemblies/store_app_block_view_test.js     |     47 +
 .../views/main/service/info/summary_test.js     |      4 +-
 ambari-web/vendor/scripts/highlight.pack.js     |      2 +
 ambari-web/vendor/styles/highlight.css          |     99 +
 contrib/views/hive-next/pom.xml                 |    369 +
 .../apache/ambari/view/hive2/BaseService.java   |     54 +
 .../ambari/view/hive2/ConnectionDelegate.java   |     40 +
 .../ambari/view/hive2/ConnectionFactory.java    |    131 +
 .../ambari/view/hive2/ConnectionSystem.java     |    100 +
 .../apache/ambari/view/hive2/HelpService.java   |    118 +
 .../view/hive2/HiveJdbcConnectionDelegate.java  |    144 +
 .../apache/ambari/view/hive2/HiveViewImpl.java  |     50 +
 .../ambari/view/hive2/PropertyValidator.java    |     98 +
 .../org/apache/ambari/view/hive2/TestBean.java  |     36 +
 .../view/hive2/actor/AsyncJdbcConnector.java    |    191 +
 .../view/hive2/actor/AsyncQueryExecutor.java    |     92 +
 .../ambari/view/hive2/actor/DeathWatch.java     |     54 +
 .../view/hive2/actor/GetResultHolder.java       |     47 +
 .../ambari/view/hive2/actor/HiveActor.java      |     50 +
 .../ambari/view/hive2/actor/JdbcConnector.java  |    305 +
 .../ambari/view/hive2/actor/LogAggregator.java  |    109 +
 .../view/hive2/actor/OperationController.java   |    438 +
 .../view/hive2/actor/ResultSetIterator.java     |    219 +
 .../view/hive2/actor/SyncJdbcConnector.java     |    174 +
 .../ambari/view/hive2/actor/YarnAtsParser.java  |     32 +
 .../view/hive2/actor/message/AdvanceCursor.java |     32 +
 .../hive2/actor/message/AssignResultSet.java    |     48 +
 .../hive2/actor/message/AssignStatement.java    |     46 +
 .../view/hive2/actor/message/AsyncJob.java      |     52 +
 .../view/hive2/actor/message/Connect.java       |     56 +
 .../view/hive2/actor/message/CursorReset.java   |     22 +
 .../ambari/view/hive2/actor/message/DDLJob.java |     73 +
 .../view/hive2/actor/message/ExecuteJob.java    |     38 +
 .../view/hive2/actor/message/ExecuteQuery.java  |     23 +
 .../view/hive2/actor/message/FetchError.java    |     42 +
 .../view/hive2/actor/message/FetchResult.java   |     42 +
 .../actor/message/GetColumnMetadataJob.java     |     60 +
 .../view/hive2/actor/message/GetMoreLogs.java   |     22 +
 .../view/hive2/actor/message/HiveJob.java       |     63 +
 .../view/hive2/actor/message/HiveMessage.java   |     53 +
 .../actor/message/JobExecutionCompleted.java    |     21 +
 .../view/hive2/actor/message/JobRejected.java   |     44 +
 .../view/hive2/actor/message/JobSubmitted.java  |     38 +
 .../actor/message/LogAggregationFinished.java   |     21 +
 .../view/hive2/actor/message/RegisterActor.java |     34 +
 .../view/hive2/actor/message/ResetCursor.java   |     22 +
 .../view/hive2/actor/message/ResultReady.java   |     47 +
 .../actor/message/StartLogAggregation.java      |     21 +
 .../view/hive2/actor/message/SyncJob.java       |     27 +
 .../actor/message/job/AsyncExecutionFailed.java |     46 +
 .../actor/message/job/ExecutionFailed.java      |     31 +
 .../view/hive2/actor/message/job/Failure.java   |     37 +
 .../hive2/actor/message/job/FetchFailed.java    |     31 +
 .../view/hive2/actor/message/job/Next.java      |     22 +
 .../hive2/actor/message/job/NoMoreItems.java    |     21 +
 .../view/hive2/actor/message/job/NoResult.java  |     21 +
 .../view/hive2/actor/message/job/Result.java    |     43 +
 .../actor/message/job/ResultSetHolder.java      |     33 +
 .../hive2/actor/message/lifecycle/CleanUp.java  |     21 +
 .../message/lifecycle/DestroyConnector.java     |     52 +
 .../actor/message/lifecycle/FreeConnector.java  |     53 +
 .../message/lifecycle/InactivityCheck.java      |     21 +
 .../actor/message/lifecycle/KeepAlive.java      |     21 +
 .../lifecycle/TerminateInactivityCheck.java     |     21 +
 .../backgroundjobs/BackgroundJobController.java |     84 +
 .../view/hive2/client/AsyncJobRunner.java       |     36 +
 .../view/hive2/client/AsyncJobRunnerImpl.java   |    115 +
 .../view/hive2/client/ColumnDescription.java    |     45 +
 .../hive2/client/ColumnDescriptionExtended.java |     74 +
 .../hive2/client/ColumnDescriptionShort.java    |     53 +
 .../view/hive2/client/ConnectionConfig.java     |     51 +
 .../apache/ambari/view/hive2/client/Cursor.java |     30 +
 .../ambari/view/hive2/client/DDLDelegator.java  |     36 +
 .../view/hive2/client/DDLDelegatorImpl.java     |    242 +
 .../ambari/view/hive2/client/EmptyCursor.java   |    110 +
 .../view/hive2/client/HiveAuthCredentials.java  |     31 +
 .../hive2/client/HiveAuthRequiredException.java |     27 +
 .../client/HiveClientAuthRequiredException.java |     25 +
 .../view/hive2/client/HiveClientException.java  |     25 +
 .../client/HiveClientRuntimeException.java      |     25 +
 .../view/hive2/client/NonPersistentCursor.java  |    153 +
 .../view/hive2/client/PersistentCursor.java     |     87 +
 .../apache/ambari/view/hive2/client/Row.java    |     74 +
 .../hive2/exceptions/NotConnectedException.java |     28 +
 .../hive2/internal/AsyncExecutionFailure.java   |     23 +
 .../hive2/internal/AsyncExecutionSuccess.java   |     25 +
 .../ambari/view/hive2/internal/Connectable.java |     59 +
 .../hive2/internal/ConnectionException.java     |     25 +
 .../hive2/internal/ConnectionProperties.java    |     94 +
 .../view/hive2/internal/ConnectionSupplier.java |     37 +
 .../view/hive2/internal/ContextSupplier.java    |     37 +
 .../hive2/internal/DataStorageSupplier.java     |     42 +
 .../view/hive2/internal/DefaultSupplier.java    |     62 +
 .../ambari/view/hive2/internal/Either.java      |     78 +
 .../view/hive2/internal/HdfsApiSupplier.java    |     59 +
 .../hive2/internal/HiveConnectionWrapper.java   |    109 +
 .../ambari/view/hive2/internal/HiveQuery.java   |     71 +
 .../ambari/view/hive2/internal/HiveResult.java  |    160 +
 .../ambari/view/hive2/internal/HiveTask.java    |     53 +
 .../view/hive2/internal/HiveTaskMessage.java    |    118 +
 .../hive2/persistence/DataStoreStorage.java     |    172 +
 .../view/hive2/persistence/IStorageFactory.java |     23 +
 .../persistence/InstanceKeyValueStorage.java    |    132 +
 .../view/hive2/persistence/KeyValueStorage.java |    163 +
 .../hive2/persistence/LocalKeyValueStorage.java |     69 +
 .../persistence/PersistentConfiguration.java    |     52 +
 .../ambari/view/hive2/persistence/Storage.java  |     77 +
 .../utils/ContextConfigurationAdapter.java      |    260 +
 .../persistence/utils/FilteringStrategy.java    |     32 +
 .../view/hive2/persistence/utils/Indexed.java   |     36 +
 .../hive2/persistence/utils/ItemNotFound.java   |     25 +
 .../utils/OnlyOwnersFilteringStrategy.java      |     38 +
 .../view/hive2/persistence/utils/Owned.java     |     36 +
 .../persistence/utils/PersonalResource.java     |     22 +
 .../hive2/persistence/utils/StorageFactory.java |     69 +
 .../hive2/resources/CRUDResourceManager.java    |    131 +
 .../view/hive2/resources/IResourceManager.java  |     37 +
 .../resources/PersonalCRUDResourceManager.java  |     99 +
 .../resources/SharedCRUDResourceManager.java    |     44 +
 .../resources/browser/HiveBrowserService.java   |    261 +
 .../hive2/resources/files/FileResource.java     |     70 +
 .../view/hive2/resources/files/FileService.java |    250 +
 .../view/hive2/resources/jobs/Aggregator.java   |    231 +
 .../resources/jobs/JobResourceProvider.java     |    117 +
 .../view/hive2/resources/jobs/JobService.java   |    612 +
 .../jobs/ModifyNotificationDelegate.java        |     23 +
 .../ModifyNotificationInvocationHandler.java    |     40 +
 .../jobs/NoOperationStatusSetException.java     |     23 +
 .../hive2/resources/jobs/ProgressRetriever.java |     66 +
 .../jobs/ResultsPaginationController.java       |    284 +
 .../hive2/resources/jobs/atsJobs/ATSParser.java |    184 +
 .../jobs/atsJobs/ATSParserFactory.java          |     42 +
 .../jobs/atsJobs/ATSRequestsDelegate.java       |     43 +
 .../jobs/atsJobs/ATSRequestsDelegateImpl.java   |    146 +
 .../resources/jobs/atsJobs/HiveQueryId.java     |     42 +
 .../resources/jobs/atsJobs/IATSParser.java      |     33 +
 .../hive2/resources/jobs/atsJobs/TezDagId.java  |     26 +
 .../resources/jobs/atsJobs/TezVertexId.java     |     24 +
 .../view/hive2/resources/jobs/rm/RMParser.java  |    129 +
 .../resources/jobs/rm/RMParserFactory.java      |     48 +
 .../resources/jobs/rm/RMRequestsDelegate.java   |     31 +
 .../jobs/rm/RMRequestsDelegateImpl.java         |     99 +
 .../jobs/viewJobs/IJobControllerFactory.java    |     23 +
 .../view/hive2/resources/jobs/viewJobs/Job.java |    131 +
 .../resources/jobs/viewJobs/JobController.java  |     44 +
 .../jobs/viewJobs/JobControllerFactory.java     |     40 +
 .../jobs/viewJobs/JobControllerImpl.java        |    309 +
 .../hive2/resources/jobs/viewJobs/JobImpl.java  |    322 +
 .../jobs/viewJobs/JobResourceManager.java       |    108 +
 .../resources/resources/FileResourceItem.java   |     78 +
 .../resources/FileResourceResourceManager.java  |     65 +
 .../resources/FileResourceResourceProvider.java |    110 +
 .../resources/FileResourceService.java          |    180 +
 .../resources/savedQueries/SavedQuery.java      |     96 +
 .../savedQueries/SavedQueryResourceManager.java |    162 +
 .../SavedQueryResourceProvider.java             |    113 +
 .../savedQueries/SavedQueryService.java         |    230 +
 .../ambari/view/hive2/resources/udfs/UDF.java   |     87 +
 .../resources/udfs/UDFResourceManager.java      |     65 +
 .../resources/udfs/UDFResourceProvider.java     |    111 +
 .../view/hive2/resources/udfs/UDFService.java   |    193 +
 .../uploads/ColumnDescriptionImpl.java          |    119 +
 .../hive2/resources/uploads/HiveFileType.java   |     30 +
 .../resources/uploads/TableDataReader.java      |     86 +
 .../hive2/resources/uploads/TableInput.java     |     90 +
 .../resources/uploads/UploadFromHdfsInput.java  |     91 +
 .../hive2/resources/uploads/UploadService.java  |    463 +
 .../resources/uploads/parsers/DataParser.java   |     72 +
 .../uploads/parsers/EndOfDocumentException.java |     41 +
 .../resources/uploads/parsers/IParser.java      |     44 +
 .../resources/uploads/parsers/ParseOptions.java |     49 +
 .../resources/uploads/parsers/ParseUtils.java   |    133 +
 .../hive2/resources/uploads/parsers/Parser.java |    154 +
 .../resources/uploads/parsers/PreviewData.java  |     56 +
 .../resources/uploads/parsers/RowIterator.java  |     96 +
 .../uploads/parsers/RowMapIterator.java         |     29 +
 .../uploads/parsers/csv/CSVIterator.java        |     57 +
 .../uploads/parsers/csv/CSVParser.java          |     55 +
 .../uploads/parsers/json/JSONIterator.java      |    160 +
 .../uploads/parsers/json/JSONParser.java        |     85 +
 .../uploads/parsers/xml/XMLIterator.java        |    195 +
 .../uploads/parsers/xml/XMLParser.java          |    100 +
 .../uploads/query/DeleteQueryInput.java         |     48 +
 .../uploads/query/InsertFromQueryInput.java     |     68 +
 .../resources/uploads/query/LoadQueryInput.java |     67 +
 .../resources/uploads/query/QueryGenerator.java |     98 +
 .../resources/uploads/query/TableInfo.java      |     83 +
 .../utils/BadRequestFormattedException.java     |     27 +
 .../ambari/view/hive2/utils/FilePaginator.java  |    127 +
 .../hive2/utils/HiveActorConfiguration.java     |     71 +
 .../utils/HiveClientFormattedException.java     |     26 +
 .../view/hive2/utils/LoggingOutputStream.java   |     85 +
 .../MisconfigurationFormattedException.java     |     47 +
 .../hive2/utils/NotFoundFormattedException.java |     27 +
 .../hive2/utils/ServiceFormattedException.java  |    105 +
 .../view/hive2/utils/SharedObjectsFactory.java  |    185 +
 .../src/main/resources/application.conf         |     57 +
 .../src/main/resources/ui/hive-web/.bowerrc     |      4 +
 .../main/resources/ui/hive-web/.editorconfig    |     34 +
 .../src/main/resources/ui/hive-web/.ember-cli   |     27 +
 .../src/main/resources/ui/hive-web/.gitignore   |     37 +
 .../src/main/resources/ui/hive-web/.jshintrc    |     33 +
 .../src/main/resources/ui/hive-web/.travis.yml  |     38 +
 .../src/main/resources/ui/hive-web/Brocfile.js  |     54 +
 .../src/main/resources/ui/hive-web/README.md    |     14 +
 .../ui/hive-web/app/adapters/application.js     |     46 +
 .../ui/hive-web/app/adapters/database.js        |     25 +
 .../ui/hive-web/app/adapters/file-upload.js     |     31 +
 .../resources/ui/hive-web/app/adapters/file.js  |     26 +
 .../ui/hive-web/app/adapters/upload-table.js    |     93 +
 .../src/main/resources/ui/hive-web/app/app.js   |     34 +
 .../ui/hive-web/app/components/.gitkeep         |      0
 .../app/components/alert-message-widget.js      |     35 +
 .../app/components/collapsible-widget.js        |     38 +
 .../app/components/column-filter-widget.js      |     56 +
 .../app/components/date-range-widget.js         |     85 +
 .../hive-web/app/components/expander-widget.js  |     36 +
 .../hive-web/app/components/extended-input.js   |     50 +
 .../ui/hive-web/app/components/file-upload.js   |     25 +
 .../ui/hive-web/app/components/input-header.js  |     61 +
 .../ui/hive-web/app/components/job-tr-view.js   |     41 +
 .../ui/hive-web/app/components/modal-widget.js  |     58 +
 .../ui/hive-web/app/components/navbar-widget.js |     42 +
 .../ui/hive-web/app/components/no-bubbling.js   |     31 +
 .../ui/hive-web/app/components/notify-widget.js |     31 +
 .../app/components/number-range-widget.js       |     70 +
 .../ui/hive-web/app/components/panel-widget.js  |     30 +
 .../hive-web/app/components/popover-widget.js   |     34 +
 .../hive-web/app/components/progress-widget.js  |     30 +
 .../ui/hive-web/app/components/query-editor.js  |    129 +
 .../ui/hive-web/app/components/radio-button.js  |     39 +
 .../ui/hive-web/app/components/select-widget.js |     66 +
 .../ui/hive-web/app/components/tabs-widget.js   |     68 +
 .../ui/hive-web/app/components/tree-view.js     |     23 +
 .../hive-web/app/components/typeahead-widget.js |    108 +
 .../ui/hive-web/app/components/udf-tr-view.js   |     81 +
 .../app/components/visualization-tabs-widget.js |     56 +
 .../ui/hive-web/app/controllers/.gitkeep        |      0
 .../ui/hive-web/app/controllers/application.js  |     26 +
 .../ui/hive-web/app/controllers/databases.js    |    457 +
 .../ui/hive-web/app/controllers/history.js      |    172 +
 .../ui/hive-web/app/controllers/index.js        |    731 +
 .../controllers/index/history-query/explain.js  |    134 +
 .../app/controllers/index/history-query/logs.js |    108 +
 .../controllers/index/history-query/results.js  |    238 +
 .../ui/hive-web/app/controllers/insert-udfs.js  |     58 +
 .../ui/hive-web/app/controllers/messages.js     |     41 +
 .../ui/hive-web/app/controllers/modal-delete.js |     33 +
 .../app/controllers/modal-save-query.js         |     42 +
 .../ui/hive-web/app/controllers/modal-save.js   |     34 +
 .../ui/hive-web/app/controllers/open-queries.js |    397 +
 .../ui/hive-web/app/controllers/queries.js      |    125 +
 .../ui/hive-web/app/controllers/query-tabs.js   |    176 +
 .../ui/hive-web/app/controllers/settings.js     |     69 +
 .../ui/hive-web/app/controllers/splash.js       |    126 +
 .../ui/hive-web/app/controllers/tez-ui.js       |    106 +
 .../ui/hive-web/app/controllers/udfs.js         |    143 +
 .../ui/hive-web/app/controllers/upload-table.js |    740 +
 .../hive-web/app/controllers/visual-explain.js  |     64 +
 .../app/controllers/visualization-ui.js         |    134 +
 .../resources/ui/hive-web/app/helpers/.gitkeep  |      0
 .../ui/hive-web/app/helpers/all-uppercase.js    |     25 +
 .../ui/hive-web/app/helpers/code-helper.js      |     28 +
 .../ui/hive-web/app/helpers/date-binding.js     |     27 +
 .../hive-web/app/helpers/format-column-type.js  |     39 +
 .../ui/hive-web/app/helpers/log-helper.js       |     28 +
 .../ui/hive-web/app/helpers/path-binding.js     |     29 +
 .../hive-web/app/helpers/preformatted-string.js |     28 +
 .../ui/hive-web/app/helpers/tb-helper.js        |     33 +
 .../main/resources/ui/hive-web/app/index.html   |     42 +
 .../ui/hive-web/app/initializers/i18n.js        |    269 +
 .../ui/hive-web/app/mixins/filterable.js        |    106 +
 .../ui/hive-web/app/mixins/sortable.js          |     31 +
 .../resources/ui/hive-web/app/models/.gitkeep   |      0
 .../ui/hive-web/app/models/database.js          |     25 +
 .../ui/hive-web/app/models/file-resource.js     |     25 +
 .../resources/ui/hive-web/app/models/file.js    |     26 +
 .../resources/ui/hive-web/app/models/job.js     |     54 +
 .../ui/hive-web/app/models/saved-query.js       |     29 +
 .../resources/ui/hive-web/app/models/udf.js     |     27 +
 .../main/resources/ui/hive-web/app/router.js    |     50 +
 .../resources/ui/hive-web/app/routes/.gitkeep   |      0
 .../ui/hive-web/app/routes/application.js       |     89 +
 .../resources/ui/hive-web/app/routes/history.js |     46 +
 .../app/routes/index/history-query/explain.js   |     28 +
 .../app/routes/index/history-query/index.js     |     44 +
 .../app/routes/index/history-query/logs.js      |     28 +
 .../app/routes/index/history-query/results.js   |     28 +
 .../ui/hive-web/app/routes/index/index.js       |     36 +
 .../ui/hive-web/app/routes/index/saved-query.js |     43 +
 .../resources/ui/hive-web/app/routes/loading.js |     22 +
 .../resources/ui/hive-web/app/routes/queries.js |     40 +
 .../resources/ui/hive-web/app/routes/splash.js  |     59 +
 .../resources/ui/hive-web/app/routes/udfs.js    |     36 +
 .../ui/hive-web/app/serializers/database.js     |     41 +
 .../ui/hive-web/app/serializers/file.js         |     23 +
 .../ui/hive-web/app/services/database.js        |    243 +
 .../resources/ui/hive-web/app/services/file.js  |     59 +
 .../ui/hive-web/app/services/job-progress.js    |    102 +
 .../resources/ui/hive-web/app/services/job.js   |     56 +
 .../ui/hive-web/app/services/notify.js          |    113 +
 .../ui/hive-web/app/services/session.js         |     48 +
 .../ui/hive-web/app/services/settings.js        |    175 +
 .../resources/ui/hive-web/app/styles/.gitkeep   |      0
 .../resources/ui/hive-web/app/styles/app.scss   |    680 +
 .../hive-web/app/styles/dropdown-submenu.scss   |     65 +
 .../ui/hive-web/app/styles/mixins.scss          |     28 +
 .../ui/hive-web/app/styles/notifications.scss   |     37 +
 .../ui/hive-web/app/styles/query-tabs.scss      |     69 +
 .../resources/ui/hive-web/app/styles/vars.scss  |     21 +
 .../ui/hive-web/app/templates/.gitkeep          |      0
 .../ui/hive-web/app/templates/application.hbs   |     26 +
 .../hive-web/app/templates/components/.gitkeep  |      0
 .../components/alert-message-widget.hbs         |     28 +
 .../templates/components/collapsible-widget.hbs |     33 +
 .../components/column-filter-widget.hbs         |     42 +
 .../templates/components/date-range-widget.hbs  |     22 +
 .../templates/components/expander-widget.hbs    |     31 +
 .../app/templates/components/input-header.hbs   |     20 +
 .../app/templates/components/job-tr-view.hbs    |     49 +
 .../app/templates/components/modal-widget.hbs   |     35 +
 .../app/templates/components/navbar-widget.hbs  |     45 +
 .../app/templates/components/no-bubbling.hbs    |     19 +
 .../app/templates/components/notify-widget.hbs  |     21 +
 .../components/number-range-widget.hbs          |     23 +
 .../app/templates/components/panel-widget.hbs   |     54 +
 .../app/templates/components/popover-widget.hbs |     19 +
 .../templates/components/progress-widget.hbs    |     23 +
 .../app/templates/components/query-editor.hbs   |     19 +
 .../app/templates/components/select-widget.hbs  |     39 +
 .../app/templates/components/tabs-widget.hbs    |     41 +
 .../app/templates/components/tree-view.hbs      |     28 +
 .../app/templates/components/udf-tr-view.hbs    |     77 +
 .../components/visualization-tabs-widget.hbs    |     27 +
 .../app/templates/databases-search-results.hbs  |     50 +
 .../hive-web/app/templates/databases-tree.hbs   |     50 +
 .../ui/hive-web/app/templates/databases.hbs     |     54 +
 .../ui/hive-web/app/templates/history.hbs       |     63 +
 .../ui/hive-web/app/templates/index.hbs         |    110 +
 .../templates/index/history-query/explain.hbs   |     23 +
 .../app/templates/index/history-query/logs.hbs  |     19 +
 .../templates/index/history-query/results.hbs   |     56 +
 .../ui/hive-web/app/templates/insert-udfs.hbs   |     46 +
 .../ui/hive-web/app/templates/loading.hbs       |     19 +
 .../ui/hive-web/app/templates/logs.hbs          |     19 +
 .../ui/hive-web/app/templates/message.hbs       |     36 +
 .../ui/hive-web/app/templates/messages.hbs      |     32 +
 .../ui/hive-web/app/templates/modal-delete.hbs  |     21 +
 .../hive-web/app/templates/modal-save-query.hbs |     24 +
 .../ui/hive-web/app/templates/modal-save.hbs    |     21 +
 .../ui/hive-web/app/templates/notification.hbs  |     23 +
 .../ui/hive-web/app/templates/open-queries.hbs  |     23 +
 .../ui/hive-web/app/templates/queries.hbs       |     96 +
 .../ui/hive-web/app/templates/query-tabs.hbs    |     28 +
 .../ui/hive-web/app/templates/redirect.hbs      |     19 +
 .../ui/hive-web/app/templates/settings.hbs      |     70 +
 .../ui/hive-web/app/templates/splash.hbs        |    102 +
 .../ui/hive-web/app/templates/tez-ui.hbs        |     31 +
 .../ui/hive-web/app/templates/udfs.hbs          |     53 +
 .../ui/hive-web/app/templates/upload-table.hbs  |    168 +
 .../hive-web/app/templates/visual-explain.hbs   |     93 +
 .../hive-web/app/templates/visualization-ui.hbs |     37 +
 .../ui/hive-web/app/transforms/date.js          |     49 +
 .../ui/hive-web/app/utils/constants.js          |    233 +
 .../ui/hive-web/app/utils/dag-rules.js          |    141 +
 .../ui/hive-web/app/utils/functions.js          |    139 +
 .../resources/ui/hive-web/app/views/.gitkeep    |      0
 .../resources/ui/hive-web/app/views/index.js    |     28 +
 .../resources/ui/hive-web/app/views/message.js  |     36 +
 .../resources/ui/hive-web/app/views/messages.js |     37 +
 .../ui/hive-web/app/views/notification.js       |     51 +
 .../resources/ui/hive-web/app/views/tez-ui.js   |     37 +
 .../ui/hive-web/app/views/visual-explain.js     |    461 +
 .../ui/hive-web/app/views/visualization-ui.js   |     37 +
 .../main/resources/ui/hive-web/big_tables.js    |     54 +
 .../src/main/resources/ui/hive-web/bower.json   |     28 +
 .../resources/ui/hive-web/config/environment.js |     70 +
 .../src/main/resources/ui/hive-web/package.json |     47 +
 .../src/main/resources/ui/hive-web/testem.json  |     10 +
 .../main/resources/ui/hive-web/tests/.jshintrc  |     74 +
 .../ui/hive-web/tests/blanket-options.js        |     36 +
 .../ui/hive-web/tests/helpers/api-mock.js       |    291 +
 .../ui/hive-web/tests/helpers/resolver.js       |     29 +
 .../ui/hive-web/tests/helpers/start-app.js      |     43 +
 .../resources/ui/hive-web/tests/img/spinner.gif |    Bin 0 -> 11435 bytes
 .../main/resources/ui/hive-web/tests/index.html |     71 +
 .../hive-web/tests/integration/database-test.js |    103 +
 .../hive-web/tests/integration/history-test.js  |     95 +
 .../tests/integration/query-editor-test.js      |    106 +
 .../tests/integration/saved-queries-test.js     |    126 +
 .../hive-web/tests/integration/tez-ui-test.js   |     49 +
 .../ui/hive-web/tests/integration/udfs-test.js  |     91 +
 .../resources/ui/hive-web/tests/test-helper.js  |     24 +
 .../resources/ui/hive-web/tests/unit/.gitkeep   |      0
 .../hive-web/tests/unit/adapters/application.js |     48 +
 .../ui/hive-web/tests/unit/adapters/file.js     |     39 +
 .../components/alert-message-widget-test.js     |     91 +
 .../unit/components/collapsible-widget-test.js  |     46 +
 .../components/column-filter-widget-test.js     |    138 +
 .../unit/components/date-range-widget-test.js   |    132 +
 .../unit/components/expander-widget-test.js     |     59 +
 .../unit/components/extended-input-test.js      |     81 +
 .../tests/unit/components/job-tr-view-test.js   |     62 +
 .../tests/unit/components/modal-widget-test.js  |     69 +
 .../tests/unit/components/no-bubbling-test.js   |     44 +
 .../unit/components/number-range-widget-test.js |     70 +
 .../unit/components/popover-widget-test.js      |     36 +
 .../unit/components/progress-widget-test.js     |     40 +
 .../tests/unit/components/query-editor-test.js  |     52 +
 .../tests/unit/components/select-widget-test.js |    158 +
 .../tests/unit/components/tabs-wiget-test.js    |    117 +
 .../unit/components/typeahead-widget-test.js    |     46 +
 .../tests/unit/controllers/databases-test.js    |    276 +
 .../tests/unit/controllers/history-test.js      |    117 +
 .../tests/unit/controllers/index-test.js        |    328 +
 .../tests/unit/controllers/insert-udfs-test.js  |     68 +
 .../tests/unit/controllers/messages-test.js     |     53 +
 .../tests/unit/controllers/open-queries-test.js |    102 +
 .../tests/unit/controllers/queries-test.js      |     35 +
 .../tests/unit/controllers/settings-test.js     |    136 +
 .../tests/unit/controllers/tez-ui-test.js       |     98 +
 .../tests/unit/controllers/udfs-test.js         |     60 +
 .../tests/unit/helpers/path-binding-test.js     |     35 +
 .../hive-web/tests/unit/services/notify-test.js |    155 +
 .../tests/unit/services/settings-test.js        |    155 +
 .../tests/unit/views/visual-explain-test.js     |    106 +
 .../main/resources/ui/hive-web/vendor/.gitkeep  |      0
 .../vendor/codemirror/codemirror-min.js         |     17 +
 .../hive-web/vendor/codemirror/codemirror.css   |    309 +
 .../ui/hive-web/vendor/codemirror/show-hint.css |     38 +
 .../ui/hive-web/vendor/codemirror/show-hint.js  |    389 +
 .../ui/hive-web/vendor/codemirror/sql-hint.js   |    192 +
 .../resources/ui/hive-web/vendor/dagre.min.js   |     27 +
 .../src/main/resources/view.log4j.properties    |     31 +
 .../views/hive-next/src/main/resources/view.xml |    298 +
 .../ambari/view/hive2/AsyncQueriesTest.java     |    124 +
 .../ambari/view/hive2/InactivityTest.java       |    109 +
 .../apache/ambari/view/hive2/Mocksupport.java   |     94 +
 .../ambari/view/hive2/SyncQueriesTest.java      |    141 +
 .../ambari/view/hive/PropertyValidator.java     |      2 +-
 .../ambari/view/pig/PropertyValidator.java      |      2 +-
 contrib/views/pom.xml                           |      1 +
 pom.xml                                         |      3 +
 855 files changed, 266286 insertions(+), 1355 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
index 034b113..20bd25c 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
@@ -105,7 +105,10 @@ angular.module('ambariAdminConsole')
        Cluster.getAllClusters().then(function (clusters) {
          if(clusters.length >0){
            clusters.forEach(function(cluster) {
-             $scope.clusters.push(cluster.Clusters.cluster_name)
+             $scope.clusters.push({
+              "name" : cluster.Clusters.cluster_name,
+              "id" : cluster.Clusters.cluster_id
+             })
            });
            $scope.noLocalClusterAvailible = false;
            if($scope.clusterConfigurable){
@@ -122,7 +125,10 @@ angular.module('ambariAdminConsole')
          RemoteCluster.listAll().then(function (clusters) {
            if(clusters.length >0){
              clusters.forEach(function(cluster) {
-               $scope.remoteClusters.push(cluster.ClusterInfo.name)
+               $scope.remoteClusters.push({
+                "name" : cluster.ClusterInfo.name,
+                "id" : cluster.ClusterInfo.cluster_id
+               })
              });
              $scope.noRemoteClusterAvailible = false;
            }else{
@@ -153,16 +159,17 @@ angular.module('ambariAdminConsole')
       switch($scope.instance.clusterType) {
         case 'LOCAL_AMBARI':
           console.log($scope.cluster);
-          $scope.instance.clusterName = $scope.cluster;
+          $scope.instance.clusterId = $scope.cluster.id;
           break;
         case 'REMOTE_AMBARI':
           console.log($scope.data.remoteCluster);
-          $scope.instance.clusterName = $scope.data.remoteCluster;
+          $scope.instance.clusterId = $scope.data.remoteCluster.id;
+
           break;
         default:
-          $scope.instance.clusterName = null;
+          $scope.instance.clusterId = null;
       }
-      console.log($scope.instance.clusterName);
+      console.log($scope.instance.clusterId);
       View.createInstance($scope.instance)
         .then(function(data) {
           Alert.success($t('views.alerts.instanceCreated', {instanceName: $scope.instance.instance_name}));

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
index 2b1fb3b..5a0c226 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
@@ -63,12 +63,21 @@ angular.module('ambariAdminConsole')
 
     function initCtrlVariables(instance) {
        $scope.data.clusterType = instance.ViewInstanceInfo.cluster_type;
+       var clusterId = instance.ViewInstanceInfo.cluster_handle;
        switch($scope.data.clusterType) {
           case 'LOCAL_AMBARI':
-            $scope.cluster = instance.ViewInstanceInfo.cluster_handle;
+            $scope.clusters.forEach(function(cluster){
+              if(cluster.id == clusterId){
+                $scope.cluster = cluster;
+              }
+            })
             break;
           case 'REMOTE_AMBARI':
-            $scope.data.remoteCluster = instance.ViewInstanceInfo.cluster_handle;
+            $scope.remoteClusters.forEach(function(cluster){
+              if(cluster.id == clusterId){
+                $scope.data.remoteCluster = cluster;
+              }
+            })
             break;
        }
       $scope.originalClusterType = $scope.data.clusterType;
@@ -203,7 +212,10 @@ angular.module('ambariAdminConsole')
     Cluster.getAllClusters().then(function (clusters) {
       if(clusters.length >0){
         clusters.forEach(function(cluster) {
-          $scope.clusters.push(cluster.Clusters.cluster_name)
+          $scope.clusters.push({
+            "name" : cluster.Clusters.cluster_name,
+            "id" : cluster.Clusters.cluster_id
+          })
         });
         $scope.noLocalClusterAvailible = false;
       }else{
@@ -218,7 +230,10 @@ angular.module('ambariAdminConsole')
       RemoteCluster.listAll().then(function (clusters) {
         if(clusters.length >0){
           clusters.forEach(function(cluster) {
-            $scope.remoteClusters.push(cluster.ClusterInfo.name)
+            $scope.remoteClusters.push({
+              "name" : cluster.ClusterInfo.name,
+              "id" : cluster.ClusterInfo.cluster_id
+            })
           });
           $scope.noRemoteClusterAvailible = false;
           }else{
@@ -319,10 +334,11 @@ angular.module('ambariAdminConsole')
 
         switch($scope.data.clusterType) {
           case 'LOCAL_AMBARI':
-            data.ViewInstanceInfo.cluster_handle = $scope.cluster;
+            data.ViewInstanceInfo.cluster_handle = $scope.cluster.id;
             break;
           case 'REMOTE_AMBARI':
-            data.ViewInstanceInfo.cluster_handle = $scope.data.remoteCluster;
+            data.ViewInstanceInfo.cluster_handle = $scope.data.remoteCluster.id;
+            break;
             break;
           default :
             data.ViewInstanceInfo.cluster_handle = null;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersEditCtrl.js
index 5420ae5..ec2915e 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersEditCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/remoteClusters/RemoteClustersEditCtrl.js
@@ -28,6 +28,9 @@ angular.module('ambariAdminConsole')
     var modalInstance = $modal.open({
       templateUrl: 'views/remoteClusters/modals/changePassword.html',
       resolve: {
+        clusterId: function() {
+          return $scope.cluster.cluster_id;
+        },
         clusterName: function() {
           return $scope.cluster.cluster_name;
         },
@@ -38,7 +41,7 @@ angular.module('ambariAdminConsole')
           return $scope.cluster.cluster_user;
         }
       },
-      controller: ['$scope', 'clusterName', 'clusterUrl', 'clusterUser', 'Settings','Alert',  function($scope, clusterName, clusterUrl , clusterUser , Settings, Alert) {
+      controller: ['$scope', 'clusterId' ,'clusterName', 'clusterUrl', 'clusterUser', 'Settings','Alert',  function($scope, clusterId, clusterName, clusterUrl , clusterUser , Settings, Alert) {
         $scope.passwordData = {
           password: '',
           currentUserName: clusterUser || ''
@@ -46,6 +49,7 @@ angular.module('ambariAdminConsole')
 
         $scope.form = {};
 
+        $scope.clusterId = clusterId;
         $scope.currentUser = clusterUser;
         $scope.clusterName = clusterName;
         $scope.clusterUrl = clusterUrl;
@@ -58,10 +62,11 @@ angular.module('ambariAdminConsole')
 
             var payload = {
               "ClusterInfo" :{
+                "cluster_id" : $scope.clusterId,
                 "name" : $scope.clusterName,
                 "url" : $scope.clusterUrl,
                 "username" : $scope.passwordData.currentUserName,
-                "password" : $scope.passwordData.password //This field will go once backend API changes are done.
+                "password" : $scope.passwordData.password
               }
             };
 
@@ -125,6 +130,7 @@ angular.module('ambariAdminConsole')
     if ($scope.form.$valid){
       var payload = {
         "ClusterInfo" :{
+          "cluster_id" : $scope.cluster.cluster_id,
           "name" : $scope.cluster.cluster_name,
           "url" : $scope.cluster.cluster_url,
           "username" : $scope.cluster.cluster_user
@@ -157,7 +163,8 @@ angular.module('ambariAdminConsole')
   $scope.fetchRemoteClusterDetails = function (clusterName) {
 
     RemoteCluster.getDetails(clusterName).then(function(response) {
-        $scope.cluster.cluster_name = response.ClusterInfo.name
+        $scope.cluster.cluster_id = response.ClusterInfo.cluster_id;
+        $scope.cluster.cluster_name = response.ClusterInfo.name;
         $scope.cluster.cluster_url = response.ClusterInfo.url;
         $scope.cluster.cluster_user = response.ClusterInfo.username;
       })

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js
index 0bf73d5..c1cf221 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js
@@ -82,7 +82,7 @@ angular.module('ambariAdminConsole')
 
     getAllClusters: function() {
       var deferred = $q.defer();
-      $http.get(Settings.baseUrl + '/clusters', {mock: 'cluster/clusters.json'})
+      $http.get(Settings.baseUrl + '/clusters?fields=Clusters/cluster_id', {mock: 'cluster/clusters.json'})
       .then(function(data, status, headers) {
         deferred.resolve(data.data.items);
       })

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RemoteCluster.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RemoteCluster.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RemoteCluster.js
index 1c5f588..49c6abc 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RemoteCluster.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RemoteCluster.js
@@ -119,7 +119,7 @@ angular.module('ambariAdminConsole')
       var deferred = $q.defer();
 
       /* TODO :: Add params like RemoteCluster.matches and &from , &page_size */
-      $http.get(Settings.baseUrl + "/remoteclusters?fields=ClusterInfo/services")
+      $http.get(Settings.baseUrl + "/remoteclusters?fields=ClusterInfo/services,ClusterInfo/cluster_id")
         .success(function(response) {
           deferred.resolve(response.items);
         })

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
index dfe7ba8..bb9d624 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
@@ -327,8 +327,8 @@ angular.module('ambariAdminConsole')
     data.properties = settings;
     data.cluster_type = instanceInfo.clusterType;
 
-    if(instanceInfo.clusterName != null) {
-      data.cluster_handle = instanceInfo.clusterName;
+    if(instanceInfo.clusterId != null) {
+      data.cluster_handle = instanceInfo.clusterId;
     } else {
       angular.extend(data.properties, properties);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
index 051d720..924885f 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
@@ -133,7 +133,7 @@
           <label for="" class="control-label col-sm-3 ng-binding not-required" >{{'views.clusterName' | translate}}</label>
           <div>
             <div class="col-sm-9">
-              <select ng-model="cluster" ng-disabled="instance.clusterType != 'LOCAL_AMBARI' || noLocalClusterAvailible" ng-change="onClusterChange()" class="clusters-name-dropdown form-control"  ng-options="o as o for o in clusters"></select>
+              <select ng-model="cluster" ng-disabled="instance.clusterType != 'LOCAL_AMBARI' || noLocalClusterAvailible" ng-change="onClusterChange()" class="clusters-name-dropdown form-control"  ng-options="o as o.name for o in clusters"></select>
             </div>
           </div>
         </div>
@@ -154,7 +154,7 @@
           <label for="" class="control-label col-sm-3 ng-binding not-required" >{{'views.clusterName' | translate}}</label>
           <div>
             <div class="col-sm-9">
-              <select ng-model="data.remoteCluster" ng-disabled="instance.clusterType != 'REMOTE_AMBARI' || noRemoteClusterAvailable" ng-change="onClusterChange()" class="clusters-name-dropdown form-control"  ng-options="o as o for o in remoteClusters"></select>
+              <select ng-model="data.remoteCluster" ng-disabled="instance.clusterType != 'REMOTE_AMBARI' || noRemoteClusterAvailable" ng-change="onClusterChange()" class="clusters-name-dropdown form-control"  ng-options="o as o.name for o in remoteClusters"></select>
             </div>
           </div>
         </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
index 3a69a50..17b074b 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
@@ -177,7 +177,7 @@
         <label for="" class="control-label col-sm-3 ng-binding not-required" >{{'views.clusterName' | translate}}</label>
         <div>
           <div class="col-sm-9">
-            <select ng-model="cluster" ng-disabled="(data.clusterType != 'LOCAL_AMBARI') || editConfigurationDisabled" ng-change="onClusterChange()" class="clusters-name-dropdown form-control"  ng-options="o as o for o in clusters"></select>
+            <select ng-model="cluster" ng-disabled="(data.clusterType != 'LOCAL_AMBARI') || editConfigurationDisabled" ng-change="onClusterChange()" class="clusters-name-dropdown form-control"  ng-options="o as o.name for o in clusters"></select>
           </div>
         </div>
       </div>
@@ -193,7 +193,7 @@
           <label for="" class="control-label col-sm-3 ng-binding not-required" >{{'views.clusterName' | translate}}</label>
           <div>
             <div class="col-sm-9">
-              <select ng-model="data.remoteCluster" ng-disabled="(data.clusterType != 'REMOTE_AMBARI') || editConfigurationDisabled" ng-change="onClusterChange()" class="clusters-name-dropdown form-control"  ng-options="o as o for o in remoteClusters"></select>
+              <select ng-model="data.remoteCluster" ng-disabled="(data.clusterType != 'REMOTE_AMBARI') || editConfigurationDisabled" ng-change="onClusterChange()" class="clusters-name-dropdown form-control"  ng-options="o as o.name for o in remoteClusters"></select>
             </div>
           </div>
         </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/editRemoteClusterPage.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/editRemoteClusterPage.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/editRemoteClusterPage.html
index 8979cba..e3fbe9c 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/editRemoteClusterPage.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/editRemoteClusterPage.html
@@ -33,7 +33,7 @@
   <div class="form-group" ng-class="{'has-error' : form.user_name.$error.required && form.submitted}">
     <label for="clustername" class="col-sm-2 control-label">{{'views.clusterName' | translate}}</label>
     <div class="col-sm-10">
-      <input type="text" id="clustername" disabled class="form-control" name="cluster_name" ng-pattern="/[a-zA-Z0-9\-]*/" placeholder="Cluster Name" ng-model="cluster.cluster_name" required autocomplete="off">
+      <input type="text" id="clustername" class="form-control" name="cluster_name" ng-pattern="/[a-zA-Z0-9\-]*/" placeholder="Cluster Name" ng-model="cluster.cluster_name" required autocomplete="off">
       <div class="alert alert-danger top-margin" ng-show="form.cluster_name.$error.required && form.submitted"> {{'common.alerts.fieldIsRequired' | translate}}</div>
     </div>
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/CreateViewInstanceCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/CreateViewInstanceCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/CreateViewInstanceCtrl.js
index 595fcc0..117021e 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/CreateViewInstanceCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/CreateViewInstanceCtrl.js
@@ -68,7 +68,7 @@ describe('#CreateViewInstanceCtrl', function () {
     scope.version = '1.0.0';
     $httpBackend.expectGET('template/modal/backdrop.html');
     $httpBackend.expectGET('template/modal/window.html');
-    $httpBackend.whenGET(/\/api\/v1\/clusters\?_=\d+/).respond(200, {
+    $httpBackend.whenGET(/\/api\/v1\/clusters\?fields=Clusters\/cluster_id&_=\d+/).respond(200, {
       "items" : [
         {
           "Clusters" : {
@@ -78,7 +78,7 @@ describe('#CreateViewInstanceCtrl', function () {
         }
       ]
     });
-    $httpBackend.whenGET(/\/api\/v1\/remoteclusters\?fields=ClusterInfo\/services&_=\d+/).respond(200, {
+    $httpBackend.whenGET(/\/api\/v1\/remoteclusters\?fields=ClusterInfo\/services,ClusterInfo\/cluster_id&_=\d+/).respond(200, {
       "items" : [
          {
            "ClusterInfo" : {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-agent/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-agent/pom.xml b/ambari-agent/pom.xml
index c46a7d5..13fa16b 100644
--- a/ambari-agent/pom.xml
+++ b/ambari-agent/pom.xml
@@ -36,7 +36,7 @@
     <package.prefix>/usr</package.prefix>
     <package.log.dir>/var/log/ambari-agent</package.log.dir>
     <package.pid.dir>/var/run/ambari-agent</package.pid.dir>
-    <skipTests>false</skipTests>
+    <skipTests>true</skipTests>
     <agent.install.dir>/usr/lib/python2.6/site-packages/ambari_agent</agent.install.dir>
     <ambari_commons.install.dir>/usr/lib/ambari-agent/lib/ambari_commons</ambari_commons.install.dir>
     <resource_management.install.dir>/usr/lib/ambari-agent/lib/resource_management</resource_management.install.dir>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-client/python-client/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/pom.xml b/ambari-client/python-client/pom.xml
index 933304b..b5714c0 100644
--- a/ambari-client/python-client/pom.xml
+++ b/ambari-client/python-client/pom.xml
@@ -36,7 +36,7 @@
     <package.prefix>/usr</package.prefix>
     <package.log.dir>/var/log/python-client</package.log.dir>
     <package.pid.dir>/var/run/python-client</package.pid.dir>
-    <skipTests>false</skipTests>
+    <skipTests>true</skipTests>
     <install.dir>/usr/lib/python2.6/site-packages/ambari_client</install.dir>
     <lib.dir>/usr/lib/ambari-client/lib</lib.dir>
     <python.ver>python &gt;= 2.6</python.ver>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-logsearch/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-logsearch/pom.xml b/ambari-logsearch/pom.xml
index fc92acc..0cddc7e 100644
--- a/ambari-logsearch/pom.xml
+++ b/ambari-logsearch/pom.xml
@@ -41,7 +41,7 @@
     <deb.python.ver>python (&gt;= 2.6)</deb.python.ver>
     <deb.architecture>amd64</deb.architecture>
     <deb.dependency.list>${deb.python.ver}</deb.dependency.list>
-    <solr.version>5.5.0</solr.version>
+    <solr.version>5.5.1</solr.version>
   </properties>
   <build>
     <plugins>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index b488971..b069bf0 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -43,7 +43,7 @@
     <commonServicesSrcLocation>src/main/resources/common-services</commonServicesSrcLocation>
     <stacksSrcLocation>src/main/resources/stacks/${stack.distribution}</stacksSrcLocation>
     <tarballResourcesFolder>src/main/resources</tarballResourcesFolder>
-    <skipPythonTests>false</skipPythonTests>
+    <skipPythonTests>true</skipPythonTests>
     <hadoop.version>2.7.1</hadoop.version>
     <jetty.version>9.2.11.v20150529</jetty.version>
     <empty.dir>src/main/package</empty.dir> <!-- any directory in project with not very big amount of files (not to waste-load them) -->
@@ -260,6 +260,7 @@
             <exclude>src/main/resources/hive-schema-0.12.0.oracle.sql</exclude>
             <exclude>src/main/resources/db/serial</exclude>
             <exclude>src/main/resources/db/index.txt</exclude>
+            <exclude>src/main/resources/ambari.repo</exclude>
             <exclude>src/main/resources/stacks/HDP/2.1.GlusterFS/services/YARN/package/templates/exclude_hosts_list.j2</exclude>
             <exclude>src/main/windows/ambari-server.cmd</exclude>
             <exclude>src/main/windows/ambari-server.ps1</exclude>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/assemblies/server.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/assemblies/server.xml b/ambari-server/src/main/assemblies/server.xml
index 1560d8d..50e7442 100644
--- a/ambari-server/src/main/assemblies/server.xml
+++ b/ambari-server/src/main/assemblies/server.xml
@@ -315,6 +315,11 @@
     </file>
     <file>
       <fileMode>755</fileMode>
+      <source>src/main/resources/componentsMap.dat</source>
+      <outputDirectory>/var/lib/ambari-server/resources</outputDirectory>
+    </file>
+    <file>
+      <fileMode>755</fileMode>
       <source>src/main/python/bootstrap.py</source>
       <outputDirectory>/usr/lib/python2.6/site-packages/ambari_server</outputDirectory>
     </file>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/eventdb/webservice/WorkflowJsonService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/eventdb/webservice/WorkflowJsonService.java b/ambari-server/src/main/java/org/apache/ambari/eventdb/webservice/WorkflowJsonService.java
index 3ef56ab..c399df8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/eventdb/webservice/WorkflowJsonService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/eventdb/webservice/WorkflowJsonService.java
@@ -52,7 +52,6 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-@Path("/jobhistory")
 public class WorkflowJsonService {
   private static final String PREFIX = "eventdb.";
   private static final String HOSTNAME = PREFIX + "db.hostname";

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/ClusterNotFoundException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ClusterNotFoundException.java b/ambari-server/src/main/java/org/apache/ambari/server/ClusterNotFoundException.java
index cd338a0..62d0714 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/ClusterNotFoundException.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ClusterNotFoundException.java
@@ -24,4 +24,8 @@ public class ClusterNotFoundException extends ObjectNotFoundException {
   public ClusterNotFoundException(String clusterName) {
     super("Cluster not found, clusterName=" + clusterName);
   }
+
+  public ClusterNotFoundException(Long clusterId) {
+    super("Cluster not found, clusterId=" + clusterId);
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/ServiceComponentNotFoundException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ServiceComponentNotFoundException.java b/ambari-server/src/main/java/org/apache/ambari/server/ServiceComponentNotFoundException.java
index 32f3505..34146f0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/ServiceComponentNotFoundException.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ServiceComponentNotFoundException.java
@@ -23,10 +23,12 @@ public class ServiceComponentNotFoundException
     extends ObjectNotFoundException {
 
   public ServiceComponentNotFoundException (String clusterName,
-      String serviceName, String serviceComponentName) {
+      String serviceName, String stackServiceName, String serviceGroupName, String serviceComponentName) {
     super("ServiceComponent not found"
         + ", clusterName=" + clusterName
         + ", serviceName=" + serviceName
+        + ", stackServiceName=" + stackServiceName
+        + ", serviceGroupName=" + serviceGroupName
         + ", serviceComponentName=" + serviceComponentName);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/ServiceGroupNotFoundException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ServiceGroupNotFoundException.java b/ambari-server/src/main/java/org/apache/ambari/server/ServiceGroupNotFoundException.java
new file mode 100644
index 0000000..f63b6aa
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ServiceGroupNotFoundException.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.ambari.server;
+
+@SuppressWarnings("serial")
+public class ServiceGroupNotFoundException extends ObjectNotFoundException {
+
+  public ServiceGroupNotFoundException(String clusterName, String serviceGroupName) {
+    super("Service group not found"
+        + ", clusterName=" + clusterName
+        + ", serviceGroupName=" + serviceGroupName);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
index a902a2c..2f5532a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
@@ -236,13 +236,15 @@ public class HeartbeatMonitor implements Runnable {
   private StatusCommand createStatusCommand(String hostname, Cluster cluster,
                                ServiceComponentHost sch) throws AmbariException {
     String serviceName = sch.getServiceName();
+    String stackServiceName = sch.getStackServiceName();
+    String serviceGroupName = sch.getServiceGroupName();
     String componentName = sch.getServiceComponentName();
     StackId stackId = cluster.getDesiredStackVersion();
     ServiceInfo serviceInfo = ambariMetaInfo.getService(stackId.getStackName(),
-        stackId.getStackVersion(), serviceName);
+        stackId.getStackVersion(), stackServiceName);
     ComponentInfo componentInfo = ambariMetaInfo.getComponent(
             stackId.getStackName(), stackId.getStackVersion(),
-            serviceName, componentName);
+        stackServiceName, componentName);
     StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(),
         stackId.getStackVersion());
 
@@ -259,7 +261,7 @@ public class HeartbeatMonitor implements Runnable {
         .getEffectiveDesiredTags(cluster, hostname);
 
     for(Config clusterConfig: clusterConfigs) {
-      if(!clusterConfig.getType().endsWith("-env")) {
+      if(!clusterConfig.getType().contains("-env")) {
         continue;
       }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
index c6036c2..f6960a7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
@@ -305,7 +305,7 @@ public class HeartbeatProcessor extends AbstractService{
         for (ServiceComponentHost scHost : scHosts) {
           ComponentInfo componentInfo =
               ambariMetaInfo.getComponent(stackId.getStackName(),
-                  stackId.getStackVersion(), scHost.getServiceName(),
+                  stackId.getStackVersion(), scHost.getStackServiceName(),
                   scHost.getServiceComponentName());
 
           String status = scHost.getState().name();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
index 1a3aa01..33024b4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
@@ -62,6 +62,7 @@ public class ClusterResourceDefinition extends BaseResourceDefinition {
   public Set<SubResourceDefinition> getSubResourceDefinitions() {
     Set<SubResourceDefinition> setChildren = new HashSet<SubResourceDefinition>();
     setChildren.add(new SubResourceDefinition(Resource.Type.Service));
+    setChildren.add(new SubResourceDefinition(Resource.Type.ServiceGroup));
     setChildren.add(new SubResourceDefinition(Resource.Type.Host));
     setChildren.add(new SubResourceDefinition(Resource.Type.Configuration));
     setChildren.add(new SubResourceDefinition(Resource.Type.ServiceConfigVersion));

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index 9c864b6..f8c64ee 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -89,6 +89,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new ServiceResourceDefinition();
         break;
 
+      case ServiceGroup:
+        resourceDefinition = new ServiceGroupResourceDefinition();
+        break;
+
       case Host:
         resourceDefinition = mapIds.containsKey(Resource.Type.Cluster) ?
             new HostResourceDefinition() : new DetachedHostResourceDefinition();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupResourceDefinition.java
new file mode 100644
index 0000000..534c427
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupResourceDefinition.java
@@ -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.
+ */
+
+package org.apache.ambari.server.api.resources;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Service group resource definition.
+ */
+public class ServiceGroupResourceDefinition extends BaseResourceDefinition {
+
+  /**
+   * Constructor.
+   *
+   */
+  public ServiceGroupResourceDefinition() {
+    super(Resource.Type.ServiceGroup);
+  }
+
+  @Override
+  public String getPluralName() {
+    return "servicegroups";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "servicegroup";
+  }
+
+  @Override
+  public Set<SubResourceDefinition> getSubResourceDefinitions() {
+    Set<SubResourceDefinition> subs = new HashSet<SubResourceDefinition>();
+    return subs;
+  }
+}


[32/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/RemoteClustersService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RemoteClustersService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RemoteClustersService.java
index d7c7a20..ccfafd6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RemoteClustersService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RemoteClustersService.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services;
 
 import com.google.common.base.Optional;
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.security.authorization.AuthorizationException;
 
@@ -40,9 +41,12 @@ import java.util.Collections;
 /**
  * Service responsible for Remote Cluster resource requests.
  */
-@Path("/remoteclusters")
 public class RemoteClustersService extends BaseService {
 
+  public RemoteClustersService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Get the list of all Remote Clusters
    * @param headers

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/RepositoryService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RepositoryService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RepositoryService.java
index e366ad5..cdbb00e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RepositoryService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RepositoryService.java
@@ -49,6 +49,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -66,7 +67,8 @@ public class RepositoryService extends BaseService {
    *
    * @param parentKeyProperties extra properties to be inserted into created resource
    */
-  public RepositoryService(Map<Resource.Type, String> parentKeyProperties) {
+  public RepositoryService(ApiVersion apiVersion, Map<Resource.Type, String> parentKeyProperties) {
+    super(apiVersion);
     this.parentKeyProperties = parentKeyProperties;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/RepositoryVersionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RepositoryVersionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RepositoryVersionService.java
index 0a21762..c2ad906 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RepositoryVersionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RepositoryVersionService.java
@@ -33,6 +33,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -50,7 +51,8 @@ public class RepositoryVersionService extends BaseService {
    *
    * @param parentKeyProperties extra properties to be inserted into created resource
    */
-  public RepositoryVersionService(Map<Resource.Type, String> parentKeyProperties) {
+  public RepositoryVersionService(ApiVersion apiVersion, Map<Resource.Type, String> parentKeyProperties) {
+    super(apiVersion);
     this.parentKeyProperties = parentKeyProperties;
   }
 
@@ -141,7 +143,7 @@ public class RepositoryVersionService extends BaseService {
     final Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
     mapIds.putAll(parentKeyProperties);
     mapIds.put(Resource.Type.RepositoryVersion, repositoryVersionId);
-    return new OperatingSystemService(mapIds);
+    return new OperatingSystemService(m_apiVersion, mapIds);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestScheduleService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestScheduleService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestScheduleService.java
index 3ad589c..a3fd472 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestScheduleService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestScheduleService.java
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -48,7 +49,8 @@ public class RequestScheduleService extends BaseService {
    * Constructor
    * @param m_clusterName
    */
-  public RequestScheduleService(String m_clusterName) {
+  public RequestScheduleService(ApiVersion apiVersion, String m_clusterName) {
+    super(apiVersion);
     this.m_clusterName = m_clusterName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestService.java
index e1bccec..4b2d0cc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestService.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services;
 
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.GET;
@@ -39,7 +40,6 @@ import java.util.Map;
 /**
  * Service responsible for request resource requests.
  */
-@Path("/requests/")
 public class RequestService extends BaseService {
   /**
    * Parent cluster name.
@@ -47,7 +47,8 @@ public class RequestService extends BaseService {
   private String m_clusterName;
 
 
-  public RequestService() {
+  public RequestService(ApiVersion apiVersion) {
+    super(apiVersion);
   }
   
   /**
@@ -55,7 +56,8 @@ public class RequestService extends BaseService {
    *
    * @param clusterName cluster id
    */
-  public RequestService(String clusterName) {
+  public RequestService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     m_clusterName = clusterName;
   }
 
@@ -101,7 +103,7 @@ public class RequestService extends BaseService {
    */
   @Path("{requestId}/stages")
   public StageService getStageHandler(@PathParam("requestId") String requestId) {
-    return new StageService(m_clusterName, requestId);
+    return new StageService(m_apiVersion, m_clusterName, requestId);
   }
 
   /**
@@ -109,7 +111,7 @@ public class RequestService extends BaseService {
    */
   @Path("{requestId}/tasks")
   public TaskService getTaskHandler(@PathParam("requestId") String requestId) {
-    return new TaskService(m_clusterName, requestId, null);
+    return new TaskService(m_apiVersion, m_clusterName, requestId, null);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/RoleAuthorizationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RoleAuthorizationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RoleAuthorizationService.java
index 60f8a36..ad1c544 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RoleAuthorizationService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RoleAuthorizationService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.GET;
@@ -38,15 +39,14 @@ import java.util.Map;
  * The result sets returned by this service are either the full set of available authorizations or
  * those related to a particular permission.
  */
-@Path("/authorizations/")
 public class RoleAuthorizationService extends BaseService {
   private String permissionId;
 
   /**
    * Constructs a new RoleAuthorizationService that is not linked to any role (or permission)
    */
-  public RoleAuthorizationService() {
-    this(null);
+  public RoleAuthorizationService(ApiVersion apiVersion) {
+    this(apiVersion, null);
   }
 
   /**
@@ -54,7 +54,8 @@ public class RoleAuthorizationService extends BaseService {
    *
    * @param permissionId the permission id of a permission (or role)
    */
-  public RoleAuthorizationService(String permissionId) {
+  public RoleAuthorizationService(ApiVersion apiVersion, String permissionId) {
+    super(apiVersion);
     this.permissionId = permissionId;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/RootServiceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RootServiceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RootServiceService.java
index 79b266f..1f70cf8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RootServiceService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RootServiceService.java
@@ -32,11 +32,15 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
-@Path("/services/")
 public class RootServiceService extends BaseService {
-  
+
+  public RootServiceService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   @GET
   @Produces("text/plain")
   public Response getServices(String body, @Context HttpHeaders headers, @Context UriInfo ui) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java
index 03a64e2..51f5b42 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.GET;
@@ -36,7 +37,8 @@ public class ServiceConfigVersionService extends BaseService {
    */
   private String m_clusterName;
 
-  public ServiceConfigVersionService(String m_clusterName) {
+  public ServiceConfigVersionService(ApiVersion apiVersion, String m_clusterName) {
+    super(apiVersion);
     this.m_clusterName = m_clusterName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupService.java
new file mode 100644
index 0000000..b85aa97
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupService.java
@@ -0,0 +1,192 @@
+/**
+ * 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.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Service responsible for service groups resource requests.
+ */
+public class ServiceGroupService extends BaseService {
+  /**
+   * Parent cluster name.
+   */
+  private String m_clusterName;
+
+  /**
+   * Constructor.
+   *
+   * @param clusterName cluster id
+   */
+  public ServiceGroupService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
+    m_clusterName = clusterName;
+  }
+
+  /**
+   * Handles URL: /clusters/{clusterID}/servicegroups/{serviceGroupId}
+   * Get a specific service group.
+   *
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param serviceGroupName service group id
+   * @return service group resource representation
+   */
+  @GET
+  @Path("{serviceGroupName}")
+  @Produces("text/plain")
+  public Response getServiceGroup(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                             @PathParam("serviceGroupName") String serviceGroupName) {
+
+    return handleRequest(headers, body, ui, Request.Type.GET,
+        createServiceGroupResource(m_clusterName, serviceGroupName));
+  }
+
+  /**
+   * Handles URL: /clusters/{clusterId}/servicegroups
+   * Get all service groups for a cluster.
+   *
+   * @param headers http headers
+   * @param ui      uri info
+   * @return service collection resource representation
+   */
+  @GET
+  @Produces("text/plain")
+  public Response getServiceGroups(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.GET,
+        createServiceGroupResource(m_clusterName, null));
+  }
+
+  /**
+   * Handles: POST /clusters/{clusterId}/servicegroups/{serviceGroupId}
+   * Create a specific service group.
+   *
+   * @param body        http body
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param serviceGroupName service group id
+   * @return information regarding the created service
+   */
+  @POST
+  @Path("{serviceGroupName}")
+  @Produces("text/plain")
+  public Response createService(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("serviceGroupName") String serviceGroupName) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST,
+        createServiceGroupResource(m_clusterName, serviceGroupName));
+  }
+
+  /**
+   * Handles: POST /clusters/{clusterId}/servicegroups
+   * Create multiple service groups.
+   *
+   * @param body        http body
+   * @param headers     http headers
+   * @param ui          uri info
+   * @return information regarding the created service groups
+   */
+  @POST
+  @Produces("text/plain")
+  public Response createServiceGroups(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST,
+        createServiceGroupResource(m_clusterName, null));
+  }
+
+  /**
+   * Handles: PUT /clusters/{clusterId}/servicegroups/{serviceGroupId}
+   * Update a specific service group.
+   *
+   * @param body        http body
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param serviceGroupName service group id
+   * @return information regarding the updated service group
+   */
+  @PUT
+  @Path("{serviceGroupName}")
+  @Produces("text/plain")
+  public Response updateServiceGroup(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("serviceGroupName") String serviceGroupName) {
+
+    return handleRequest(headers, body, ui, Request.Type.PUT, createServiceGroupResource(m_clusterName, serviceGroupName));
+  }
+
+  /**
+   * Handles: PUT /clusters/{clusterId}/servicegroups
+   * Update multiple service groups.
+   *
+   * @param body        http body
+   * @param headers     http headers
+   * @param ui          uri info
+   * @return information regarding the updated service groups
+   */
+  @PUT
+  @Produces("text/plain")
+  public Response updateServiceGroups(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+
+    return handleRequest(headers, body, ui, Request.Type.PUT, createServiceGroupResource(m_clusterName, null));
+  }
+
+  /**
+   * Handles: DELETE /clusters/{clusterId}/servicegroups/{serviceGroupId}
+   * Delete a specific service group.
+   *
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param serviceGroupName service group id
+   * @return information regarding the deleted service group
+   */
+  @DELETE
+  @Path("{serviceGroupName}")
+  @Produces("text/plain")
+  public Response deleteService(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("serviceGroupName") String serviceGroupName) {
+
+    return handleRequest(headers, null, ui, Request.Type.DELETE, createServiceGroupResource(m_clusterName, serviceGroupName));
+  }
+
+
+  /**
+   * Create a service resource instance.
+   *
+   * @param clusterName  cluster name
+   * @param serviceGroupName  service group name
+   *
+   * @return a service resource instance
+   */
+  ResourceInstance createServiceGroupResource(String clusterName, String serviceGroupName) {
+    Map<Resource.Type,String> mapIds = new HashMap<>();
+    mapIds.put(Resource.Type.Cluster, clusterName);
+    mapIds.put(Resource.Type.ServiceGroup, serviceGroupName);
+
+    return createResource(Resource.Type.ServiceGroup, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
index ad6d68c..adbd31d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
@@ -34,6 +34,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -50,7 +51,8 @@ public class ServiceService extends BaseService {
    *
    * @param clusterName cluster id
    */
-  public ServiceService(String clusterName) {
+  public ServiceService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     m_clusterName = clusterName;
   }
 
@@ -187,7 +189,7 @@ public class ServiceService extends BaseService {
   @Path("{serviceName}/components")
   public ComponentService getComponentHandler(@PathParam("serviceName") String serviceName) {
 
-    return new ComponentService(m_clusterName, serviceName);
+    return new ComponentService(m_apiVersion, m_clusterName, serviceName);
   }
 
   /**
@@ -196,7 +198,7 @@ public class ServiceService extends BaseService {
   @Path("{serviceName}/alerts")
   public AlertService getAlertHandler(
       @PathParam("serviceName") String serviceName) {
-    return new AlertService(m_clusterName, serviceName, null);
+    return new AlertService(m_apiVersion, m_clusterName, serviceName, null);
   }
 
   /**
@@ -379,7 +381,7 @@ public class ServiceService extends BaseService {
       @Context javax.ws.rs.core.Request request,
       @PathParam("serviceName") String serviceName) {
 
-    return new AlertHistoryService(m_clusterName, serviceName, null);
+    return new AlertHistoryService(m_apiVersion, m_clusterName, serviceName, null);
   }
 
   /**
@@ -391,7 +393,7 @@ public class ServiceService extends BaseService {
    * @return a service resource instance
    */
   ResourceInstance createServiceResource(String clusterName, String serviceName) {
-    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    Map<Resource.Type,String> mapIds = new HashMap<>();
     mapIds.put(Resource.Type.Cluster, clusterName);
     mapIds.put(Resource.Type.Service, serviceName);
 
@@ -408,7 +410,7 @@ public class ServiceService extends BaseService {
    * @return an artifact resource instance
    */
   ResourceInstance createArtifactResource(String clusterName, String serviceName, String artifactName) {
-    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    Map<Resource.Type,String> mapIds = new HashMap<>();
     mapIds.put(Resource.Type.Cluster, clusterName);
     mapIds.put(Resource.Type.Service, serviceName);
     mapIds.put(Resource.Type.Artifact, artifactName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/SettingService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/SettingService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/SettingService.java
index db6f002..c8ac1a6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/SettingService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/SettingService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 
@@ -38,14 +39,13 @@ import java.util.Collections;
 /**
  * Service responsible for setting resource requests.
  */
-@Path("/settings/")
 public class SettingService extends BaseService {
 
   /**
    * Construct a SettingService.
    */
-  public SettingService() {
-
+  public SettingService(ApiVersion apiVersion) {
+    super(apiVersion);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
index 557ce98..1187167 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
@@ -22,24 +22,22 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.*;
+import javax.ws.rs.core.*;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
  * Service for stacks management.
  */
-@Path("/stacks/")
 public class StacksService extends BaseService {
 
+  public StacksService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   @GET
   @Produces("text/plain")
   public Response getStacks(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
@@ -333,7 +331,48 @@ public class StacksService extends BaseService {
     final Map<Resource.Type, String> stackProperties = new HashMap<Resource.Type, String>();
     stackProperties.put(Resource.Type.Stack, stackName);
     stackProperties.put(Resource.Type.StackVersion, stackVersion);
-    return new OperatingSystemService(stackProperties);
+    return new OperatingSystemService(m_apiVersion, stackProperties);
+  }
+
+  /**
+   * Returns host-layout recommendations for list of hosts and services.
+   *
+   * @param body http body
+   * @param headers http headers
+   * @param ui uri info
+   * @param stackName stack name
+   * @param stackVersion stack version
+   * @return recommendations for host-layout
+   */
+  @POST
+  @Path("{stackName}/versions/{stackVersion}/recommendations")
+  @Produces(MediaType.TEXT_PLAIN)
+  public Response getRecommendation(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                    @PathParam("stackName") String stackName,
+                                    @PathParam("stackVersion") String stackVersion) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST,
+        createRecommendationResource(stackName, stackVersion));
+  }
+
+  /**
+   * Returns validation of host-layout.
+   *
+   * @param body http body
+   * @param headers http headers
+   * @param ui uri info
+   * @param stackName stack name
+   * @param stackVersion stack version
+   * @return validation items if any
+   */
+  @POST
+  @Path("{stackName}/versions/{stackVersion}/validations")
+  @Produces(MediaType.TEXT_PLAIN)
+  public Response getValidation(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("stackName") String stackName, @PathParam("stackVersion") String stackVersion) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST,
+        createValidationResource(stackName, stackVersion));
   }
 
   /**
@@ -348,7 +387,7 @@ public class StacksService extends BaseService {
     final Map<Resource.Type, String> stackProperties = new HashMap<Resource.Type, String>();
     stackProperties.put(Resource.Type.Stack, stackName);
     stackProperties.put(Resource.Type.StackVersion, stackVersion);
-    return new RepositoryVersionService(stackProperties);
+    return new RepositoryVersionService(m_apiVersion, stackProperties);
   }
 
   /**
@@ -365,7 +404,7 @@ public class StacksService extends BaseService {
     final Map<Resource.Type, String> stackProperties = new HashMap<Resource.Type, String>();
     stackProperties.put(Resource.Type.Stack, stackName);
     stackProperties.put(Resource.Type.StackVersion, stackVersion);
-    return new CompatibleRepositoryVersionService(stackProperties);
+    return new CompatibleRepositoryVersionService(m_apiVersion, stackProperties);
   }
 
   ResourceInstance createStackServiceComponentResource(
@@ -497,5 +536,21 @@ public class StacksService extends BaseService {
         Collections.singletonMap(Resource.Type.Stack, stackName));
 
   }
+
+  ResourceInstance createRecommendationResource(String stackName, String stackVersion) {
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Stack, stackName);
+    mapIds.put(Resource.Type.StackVersion, stackVersion);
+
+    return createResource(Resource.Type.Recommendation, mapIds);
+  }
+
+  ResourceInstance createValidationResource(String stackName, String stackVersion) {
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Stack, stackName);
+    mapIds.put(Resource.Type.StackVersion, stackVersion);
+
+    return createResource(Resource.Type.Validation, mapIds);
+  }
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/StageService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/StageService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/StageService.java
index 6c24d4d..e82223e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/StageService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/StageService.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services;
 
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.GET;
@@ -59,7 +60,8 @@ public class StageService extends BaseService {
    * @param clusterName  cluster id
    * @param requestId    request id
    */
-  public StageService(String clusterName, String requestId) {
+  public StageService(ApiVersion apiVersion, String clusterName, String requestId) {
+    super(apiVersion);
     m_clusterName = clusterName;
     m_requestId = requestId;
   }
@@ -109,7 +111,7 @@ public class StageService extends BaseService {
    */
   @Path("{stageId}/tasks")
   public TaskService getTaskHandler(@PathParam("stageId") String stageId) {
-    return new TaskService(m_clusterName, m_requestId, stageId);
+    return new TaskService(m_apiVersion, m_clusterName, m_requestId, stageId);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/TargetClusterService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/TargetClusterService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/TargetClusterService.java
index 34c8c26..dbb8bbc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/TargetClusterService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/TargetClusterService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -37,9 +38,12 @@ import java.util.Collections;
 /**
  * DR target cluster service.
  */
-@Path("/targets/")
 public class TargetClusterService extends BaseService {
 
+  public TargetClusterService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Handles: GET /targets/{targetName}
    * Get a specific target.

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/TaskAttemptService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/TaskAttemptService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/TaskAttemptService.java
index 532a5a4..d501b14 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/TaskAttemptService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/TaskAttemptService.java
@@ -31,6 +31,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -51,7 +52,8 @@ public class TaskAttemptService extends BaseService {
    * @param jobId
    *          job id
    */
-  public TaskAttemptService(String clusterName, String workflowId, String jobId) {
+  public TaskAttemptService(ApiVersion apiVersion, String clusterName, String workflowId, String jobId) {
+    super(apiVersion);
     this.clusterName = clusterName;
     this.workflowId = workflowId;
     this.jobId = jobId;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/TaskService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/TaskService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/TaskService.java
index 9151415..e67cab7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/TaskService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/TaskService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.GET;
@@ -57,7 +58,8 @@ public class TaskService extends BaseService {
    * @param requestId    request id
    * @param stageId      stage id
    */
-  public TaskService(String clusterName, String requestId, String stageId) {
+  public TaskService(ApiVersion apiVersion, String clusterName, String requestId, String stageId) {
+    super(apiVersion);
     m_clusterName = clusterName;
     m_requestId = requestId;
     m_stageId = stageId;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeGroupService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeGroupService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeGroupService.java
index a9aa500..6e16ab3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeGroupService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeGroupService.java
@@ -30,6 +30,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -40,7 +41,8 @@ public class UpgradeGroupService extends BaseService {
   private String m_clusterName = null;
   private String m_upgradeId = null;
 
-  UpgradeGroupService(String clusterName, String upgradeId) {
+  UpgradeGroupService(ApiVersion apiVersion, String clusterName, String upgradeId) {
+    super(apiVersion);
     m_clusterName = clusterName;
     m_upgradeId = upgradeId;
   }
@@ -68,7 +70,7 @@ public class UpgradeGroupService extends BaseService {
   public UpgradeItemService getUpgradeItemService(
       @Context HttpHeaders headers,
       @PathParam("upgradeGroupId") Long groupId) {
-    return new UpgradeItemService(m_clusterName, m_upgradeId, groupId.toString());
+    return new UpgradeItemService(m_apiVersion, m_clusterName, m_upgradeId, groupId.toString());
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeItemService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeItemService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeItemService.java
index ab7e125..8e74336 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeItemService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeItemService.java
@@ -31,6 +31,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -42,7 +43,8 @@ public class UpgradeItemService extends BaseService {
   private String m_upgradeId = null;
   private String m_upgradeGroupId = null;
 
-  UpgradeItemService(String clusterName, String upgradeId, String upgradeGroupId) {
+  UpgradeItemService(ApiVersion apiVersion, String clusterName, String upgradeId, String upgradeGroupId) {
+    super(apiVersion);
     m_clusterName = clusterName;
     m_upgradeId = upgradeId;
     m_upgradeGroupId = upgradeGroupId;
@@ -94,7 +96,7 @@ public class UpgradeItemService extends BaseService {
       @Context HttpHeaders headers,
       @Context UriInfo ui,
       @PathParam("upgradeItemId") Long id) {
-    return new TaskService(m_clusterName, m_upgradeId, id.toString());
+    return new TaskService(m_apiVersion, m_clusterName, m_upgradeId, id.toString());
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeService.java
index 8b66491..31f1c79 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeService.java
@@ -32,6 +32,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -46,7 +47,8 @@ public class UpgradeService extends BaseService {
    *
    * @param clusterName the cluster name (not {@code null}).
    */
-  UpgradeService(String clusterName) {
+  UpgradeService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     m_clusterName = clusterName;
   }
 
@@ -93,7 +95,7 @@ public class UpgradeService extends BaseService {
    */
   @Path("{upgradeId}/upgrade_groups")
   public UpgradeGroupService getUpgradeGroupHandler(@PathParam("upgradeId") String upgradeId) {
-    return new UpgradeGroupService(m_clusterName, upgradeId);
+    return new UpgradeGroupService(m_apiVersion, m_clusterName, upgradeId);
   }
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeSummaryService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeSummaryService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeSummaryService.java
index b8b3e86..dda4e86 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeSummaryService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UpgradeSummaryService.java
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.GET;
@@ -44,7 +45,8 @@ public class UpgradeSummaryService extends BaseService {
    *
    * @param clusterName the cluster name (not {@code null}).
    */
-  UpgradeSummaryService(String clusterName) {
+  UpgradeSummaryService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     m_clusterName = clusterName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserAuthorizationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserAuthorizationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserAuthorizationService.java
index c288fdb..71125ad 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserAuthorizationService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserAuthorizationService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.GET;
@@ -53,7 +54,8 @@ public class UserAuthorizationService extends BaseService {
    *
    * @param username the username of the user to link thi UserAuthorizationService to
    */
-  public UserAuthorizationService(String username) {
+  public UserAuthorizationService(ApiVersion apiVersion, String username) {
+    super(apiVersion);
     this.username = username;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserPrivilegeService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserPrivilegeService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserPrivilegeService.java
index 86c4995..2cf5941 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserPrivilegeService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserPrivilegeService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import java.util.HashMap;
@@ -37,7 +38,8 @@ public class UserPrivilegeService extends PrivilegeService {
 
   private final String userName;
 
-  public UserPrivilegeService(String userName) {
+  public UserPrivilegeService(ApiVersion apiVersion, String userName) {
+    super(apiVersion);
     this.userName = userName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserService.java
index c46c373..ec58f93 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserService.java
@@ -30,6 +30,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import org.apache.commons.lang.StringUtils;
@@ -39,9 +40,12 @@ import java.util.Collections;
 /**
  * Service responsible for user requests.
  */
-@Path("/users/")
 public class UserService extends BaseService {
 
+  public UserService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Gets all users.
    * Handles: GET /users requests.
@@ -137,7 +141,7 @@ public class UserService extends BaseService {
   public PrivilegeService getPrivilegeService(@Context javax.ws.rs.core.Request request,
                                               @PathParam ("userName") String userName) {
 
-    return new UserPrivilegeService(userName);
+    return new UserPrivilegeService(m_apiVersion, userName);
   }
 
   /**
@@ -147,7 +151,7 @@ public class UserService extends BaseService {
   public ActiveWidgetLayoutService getWidgetLayoutService(@Context javax.ws.rs.core.Request request,
                                                     @PathParam ("userName") String userName) {
 
-    return new ActiveWidgetLayoutService(userName);
+    return new ActiveWidgetLayoutService(m_apiVersion, userName);
   }
 
   /**
@@ -160,7 +164,7 @@ public class UserService extends BaseService {
   @Path("{userName}/authorizations")
   public UserAuthorizationService getUserAuthorizations(
       @Context javax.ws.rs.core.Request request, @PathParam("userName") String username) {
-    return new UserAuthorizationService(username);
+    return new UserAuthorizationService(m_apiVersion, username);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/V1Service.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/V1Service.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/V1Service.java
new file mode 100644
index 0000000..dd2f088
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/V1Service.java
@@ -0,0 +1,44 @@
+/**
+ * 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.ambari.server.api.services;
+
+import org.apache.ambari.eventdb.webservice.WorkflowJsonService;
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+
+@Path("/{apiVersion : v1}")
+public class V1Service extends AbstractVersionService {
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/V2Service.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/V2Service.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/V2Service.java
new file mode 100644
index 0000000..6260a88
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/V2Service.java
@@ -0,0 +1,44 @@
+/**
+ * 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.ambari.server.api.services;
+
+import org.apache.ambari.eventdb.webservice.WorkflowJsonService;
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+
+@Path("/{apiVersion : v2}")
+public class V2Service extends AbstractVersionService {
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ValidationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ValidationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ValidationService.java
deleted file mode 100644
index 87cb6ac..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ValidationService.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * 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.ambari.server.api.services;
-
-import java.util.HashMap;
-import java.util.Map;
-
-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.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.ambari.server.api.resources.ResourceInstance;
-import org.apache.ambari.server.controller.spi.Resource;
-
-/**
- * Service responsible for validation of host-layout and configurations.
- */
-@Path("/stacks/{stackName}/versions/{stackVersion}/validations")
-public class ValidationService extends BaseService {
-
-  /**
-   * Returns validation of host-layout.
-   * 
-   * @param body http body
-   * @param headers http headers
-   * @param ui uri info
-   * @param stackName stack name
-   * @param stackVersion stack version
-   * @return validation items if any
-   */
-  @POST
-  @Produces(MediaType.TEXT_PLAIN)
-  public Response getValidation(String body, @Context HttpHeaders headers, @Context UriInfo ui,
-      @PathParam("stackName") String stackName, @PathParam("stackVersion") String stackVersion) {
-
-    return handleRequest(headers, body, ui, Request.Type.POST,
-        createValidationResource(stackName, stackVersion));
-  }
-
-  ResourceInstance createValidationResource(String stackName, String stackVersion) {
-    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
-    mapIds.put(Resource.Type.Stack, stackName);
-    mapIds.put(Resource.Type.StackVersion, stackVersion);
-
-    return createResource(Resource.Type.Validation, mapIds);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java
index 6410bd8..215e2e1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java
@@ -35,15 +35,19 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.internal.VersionDefinitionResourceProvider;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.commons.codec.binary.Base64;
 
 import com.google.gson.JsonObject;
 
-@Path("/version_definitions/")
 public class VersionDefinitionService extends BaseService {
 
+  public VersionDefinitionService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   @GET
   @Produces(MediaType.TEXT_PLAIN)
   public Response getServices(@Context HttpHeaders headers, @Context UriInfo ui) {
@@ -72,7 +76,7 @@ public class VersionDefinitionService extends BaseService {
   public OperatingSystemService getOperatingSystemsHandler(@PathParam("versionNumber") String versionNumber) {
     final Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
     mapIds.put(Resource.Type.VersionDefinition, versionNumber);
-    return new OperatingSystemService(mapIds);
+    return new OperatingSystemService(m_apiVersion, mapIds);
   }
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewDataMigrationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewDataMigrationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewDataMigrationService.java
index c6846ce..3ce4310 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewDataMigrationService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewDataMigrationService.java
@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.api.services;
 
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
 import org.apache.ambari.server.view.ViewDataMigrationContextImpl;
 import org.apache.ambari.server.view.ViewRegistry;
@@ -66,7 +67,8 @@ public class ViewDataMigrationService extends BaseService {
    * @param viewVersion    the current view version
    * @param instanceName   the current view instance name
    */
-  public ViewDataMigrationService(String viewName, String viewVersion, String instanceName) {
+  public ViewDataMigrationService(ApiVersion apiVersion, String viewName, String viewVersion, String instanceName) {
+    super(apiVersion);
     this.viewName = viewName;
     this.viewVersion = viewVersion;
     this.instanceName = instanceName;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewExternalSubResourceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewExternalSubResourceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewExternalSubResourceService.java
index 47ac0df..db136b3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewExternalSubResourceService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewExternalSubResourceService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.orm.entities.ViewEntity;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
@@ -68,7 +69,8 @@ public class ViewExternalSubResourceService  extends BaseService {
 
   // ----- Constructors ------------------------------------------------------
 
-  public ViewExternalSubResourceService(Resource.Type type, ViewInstanceEntity viewInstanceDefinition) {
+  public ViewExternalSubResourceService(ApiVersion apiVersion, Resource.Type type, ViewInstanceEntity viewInstanceDefinition) {
+    super(apiVersion);
     ViewEntity viewEntity = viewInstanceDefinition.getViewEntity();
 
     this.type         = type;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java
index fa0850e..00de534 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
 import org.apache.ambari.server.security.authorization.AuthorizationException;
@@ -66,7 +67,8 @@ public class ViewInstanceService extends BaseService {
    * @param viewName  the view id
    * @param version   the version
    */
-  public ViewInstanceService(String viewName, String version) {
+  public ViewInstanceService(ApiVersion apiVersion, String viewName, String version) {
+    super(apiVersion);
     this.viewName = viewName;
     this.version = version;
 
@@ -237,13 +239,13 @@ public class ViewInstanceService extends BaseService {
 
     hasPermission(Request.Type.valueOf(request.getMethod()), instanceName);
 
-    return new ViewPrivilegeService(viewName, version, instanceName);
+    return new ViewPrivilegeService(m_apiVersion, viewName, version, instanceName);
   }
 
   @Path("{instanceName}/migrate")
   public ViewDataMigrationService migrateData(@Context javax.ws.rs.core.Request request,
                                               @PathParam ("instanceName") String instanceName) {
-    return new ViewDataMigrationService(viewName, version, instanceName);
+    return new ViewDataMigrationService(m_apiVersion, viewName, version, instanceName);
   }
   // ----- helper methods ----------------------------------------------------
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java
index 711e85b..7ae7ca1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -60,7 +61,8 @@ public class ViewPermissionService extends BaseService {
    * @param viewName  the view id
    * @param version   the version
    */
-  public ViewPermissionService(String viewName, String version) {
+  public ViewPermissionService(ApiVersion apiVersion, String viewName, String version) {
+    super(apiVersion);
     this.viewName = viewName;
     this.version  = version;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPrivilegeService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPrivilegeService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPrivilegeService.java
index 9181467..5f3ae1c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPrivilegeService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPrivilegeService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import java.util.HashMap;
@@ -33,7 +34,8 @@ public class ViewPrivilegeService extends PrivilegeService {
   private final String viewVersion;
   private final String instanceName;
 
-  public ViewPrivilegeService(String viewName, String viewVersion, String instanceName) {
+  public ViewPrivilegeService(ApiVersion apiVersion, String viewName, String viewVersion, String instanceName) {
+    super(apiVersion);
     this.viewName = viewName;
     this.viewVersion = viewVersion;
     this.instanceName = instanceName;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewService.java
index b7edbe3..f0b9c16 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -38,9 +39,12 @@ import java.util.Collections;
 /**
  * Service responsible for view resource requests.
  */
-@Path("/views/")
 public class ViewService extends BaseService {
 
+  public ViewService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Handles: GET /views/{viewID}
    * Get a specific view.
@@ -141,7 +145,7 @@ public class ViewService extends BaseService {
    */
   @Path("{viewName}/versions")
   public ViewVersionService getInstanceHandler(@PathParam("viewName") String viewName) {
-    return new ViewVersionService(viewName);
+    return new ViewVersionService(m_apiVersion, viewName);
   }
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
index dae586b..f5fec97 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.orm.entities.ViewEntity;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
@@ -60,7 +61,8 @@ public class ViewSubResourceService extends BaseService implements ViewResourceH
   /**
    * Construct a view sub-resource service.
    */
-  public ViewSubResourceService(Resource.Type type, ViewInstanceEntity viewInstanceDefinition) {
+  public ViewSubResourceService(ApiVersion apiVersion, Resource.Type type, ViewInstanceEntity viewInstanceDefinition) {
+    super(apiVersion);
     ViewEntity viewEntity = viewInstanceDefinition.getViewEntity();
 
     this.type         = type;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewUrlsService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewUrlsService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewUrlsService.java
index 3827c18..34400a9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewUrlsService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewUrlsService.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services;
 
 import com.google.common.base.Optional;
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.security.authorization.AuthorizationException;
 
@@ -40,9 +41,12 @@ import java.util.Collections;
 /**
  * Service responsible for view resource requests.
  */
-@Path("/view/urls")
 public class ViewUrlsService extends BaseService {
 
+  public ViewUrlsService(ApiVersion apiVersion) {
+    super(apiVersion);
+  }
+
   /**
    * Get the list of all registered view URLs
    * @param headers

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java
index 8152ae6..73d8b57 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.DELETE;
@@ -54,7 +55,8 @@ public class ViewVersionService extends BaseService {
    *
    * @param viewName  the view name
    */
-  public ViewVersionService(String viewName) {
+  public ViewVersionService(ApiVersion apiVersion, String viewName) {
+    super(apiVersion);
     this.viewName = viewName;
   }
 
@@ -163,7 +165,7 @@ public class ViewVersionService extends BaseService {
   @Path("{version}/instances")
   public ViewInstanceService getInstanceHandler(@PathParam("version") String version) {
 
-    return new ViewInstanceService(viewName, version);
+    return new ViewInstanceService(m_apiVersion, viewName, version);
   }
 
   /**
@@ -176,7 +178,7 @@ public class ViewVersionService extends BaseService {
   @Path("{version}/permissions")
   public ViewPermissionService getPermissionHandler(@PathParam("version") String version) {
 
-    return new ViewPermissionService(viewName, version);
+    return new ViewPermissionService(m_apiVersion, viewName, version);
   }
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetLayoutService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetLayoutService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetLayoutService.java
index 3902236..f356896 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetLayoutService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetLayoutService.java
@@ -19,6 +19,7 @@ package org.apache.ambari.server.api.services;
 
 import com.sun.jersey.core.util.Base64;
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.*;
@@ -38,7 +39,8 @@ public class WidgetLayoutService extends BaseService {
   
   private final String clusterName;
 
-  public  WidgetLayoutService(String clusterName) {
+  public  WidgetLayoutService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     this.clusterName = clusterName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetService.java
index e6907db..29af366 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetService.java
@@ -19,6 +19,7 @@ package org.apache.ambari.server.api.services;
 
 import com.sun.jersey.core.util.Base64;
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.security.authorization.AuthorizationHelper;
 
@@ -39,7 +40,8 @@ public class WidgetService extends BaseService {
 
   private final String clusterName;
 
-  public WidgetService(String clusterName) {
+  public WidgetService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     this.clusterName = clusterName;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/WorkflowService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/WorkflowService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/WorkflowService.java
index 53ad919..5bdb977 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/WorkflowService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/WorkflowService.java
@@ -31,6 +31,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 /**
@@ -45,7 +46,8 @@ public class WorkflowService extends BaseService {
    * @param clusterName
    *          cluster id
    */
-  public WorkflowService(String clusterName) {
+  public WorkflowService(ApiVersion apiVersion, String clusterName) {
+    super(apiVersion);
     this.clusterName = clusterName;
   }
 
@@ -90,7 +92,7 @@ public class WorkflowService extends BaseService {
    */
   @Path("{workflowId}/jobs")
   public JobService getJobHandler(@PathParam("workflowId") String workflowId) {
-    return new JobService(clusterName, workflowId);
+    return new JobService(m_apiVersion, clusterName, workflowId);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
index a925d7d..8510d0c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
@@ -31,6 +31,7 @@ import org.apache.ambari.server.api.services.stackadvisor.commands.Configuration
 import org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommand;
 import org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
 import org.apache.ambari.server.api.services.stackadvisor.validations.ValidationResponse;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.configuration.Configuration;
 
 import com.google.inject.Inject;
@@ -78,10 +79,10 @@ public class StackAdvisorHelper {
       StackAdvisorRequestType requestType) throws StackAdvisorException {
     StackAdvisorCommand<ValidationResponse> command;
     if (requestType == StackAdvisorRequestType.HOST_GROUPS) {
-      command = new ComponentLayoutValidationCommand(recommendationsDir, stackAdvisorScript,
+      command = new ComponentLayoutValidationCommand(ApiVersion.v1, recommendationsDir, stackAdvisorScript,
           requestId, saRunner, metaInfo);
     } else if (requestType == StackAdvisorRequestType.CONFIGURATIONS) {
-      command = new ConfigurationValidationCommand(recommendationsDir, stackAdvisorScript,
+      command = new ConfigurationValidationCommand(ApiVersion.v1, recommendationsDir, stackAdvisorScript,
           requestId, saRunner, metaInfo);
     } else {
       throw new StackAdvisorRequestException(String.format("Unsupported request type, type=%s",
@@ -113,13 +114,13 @@ public class StackAdvisorHelper {
       StackAdvisorRequestType requestType) throws StackAdvisorException {
     StackAdvisorCommand<RecommendationResponse> command;
     if (requestType == StackAdvisorRequestType.HOST_GROUPS) {
-      command = new ComponentLayoutRecommendationCommand(recommendationsDir, stackAdvisorScript,
+      command = new ComponentLayoutRecommendationCommand(ApiVersion.v1, recommendationsDir, stackAdvisorScript,
           requestId, saRunner, metaInfo);
     } else if (requestType == StackAdvisorRequestType.CONFIGURATIONS) {
-      command = new ConfigurationRecommendationCommand(recommendationsDir, stackAdvisorScript,
+      command = new ConfigurationRecommendationCommand(ApiVersion.v1, recommendationsDir, stackAdvisorScript,
           requestId, saRunner, metaInfo);
     } else if (requestType == StackAdvisorRequestType.CONFIGURATION_DEPENDENCIES) {
-      command = new ConfigurationDependenciesRecommendationCommand(recommendationsDir, stackAdvisorScript,
+      command = new ConfigurationDependenciesRecommendationCommand(ApiVersion.v1, recommendationsDir, stackAdvisorScript,
           requestId, saRunner, metaInfo);
     } else {
       throw new StackAdvisorRequestException(String.format("Unsupported request type, type=%s",

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ComponentLayoutRecommendationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ComponentLayoutRecommendationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ComponentLayoutRecommendationCommand.java
index 0dff92b..3284c5b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ComponentLayoutRecommendationCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ComponentLayoutRecommendationCommand.java
@@ -25,6 +25,7 @@ import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
 import org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 /**
  * {@link StackAdvisorCommand} implementation for component-layout
@@ -33,12 +34,12 @@ import org.apache.ambari.server.api.services.stackadvisor.recommendations.Recomm
 public class ComponentLayoutRecommendationCommand extends
     StackAdvisorCommand<RecommendationResponse> {
 
-  public ComponentLayoutRecommendationCommand(File recommendationsDir,
+  public ComponentLayoutRecommendationCommand(ApiVersion apiVersion, File recommendationsDir,
                                               String stackAdvisorScript,
                                               int requestId,
                                               StackAdvisorRunner saRunner,
                                               AmbariMetaInfo metaInfo) {
-    super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
+    super(apiVersion,recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ComponentLayoutValidationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ComponentLayoutValidationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ComponentLayoutValidationCommand.java
index 757ebee..e836f70 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ComponentLayoutValidationCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ComponentLayoutValidationCommand.java
@@ -25,15 +25,16 @@ import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
 import org.apache.ambari.server.api.services.stackadvisor.validations.ValidationResponse;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 /**
  * {@link StackAdvisorCommand} implementation for component-layout validation.
  */
 public class ComponentLayoutValidationCommand extends StackAdvisorCommand<ValidationResponse> {
 
-  public ComponentLayoutValidationCommand(File recommendationsDir, String stackAdvisorScript,
+  public ComponentLayoutValidationCommand(ApiVersion apiVersion, File recommendationsDir, String stackAdvisorScript,
                                           int requestId, StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
-    super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
+    super(apiVersion, recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationDependenciesRecommendationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationDependenciesRecommendationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationDependenciesRecommendationCommand.java
index ae86548..d9f3083 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationDependenciesRecommendationCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationDependenciesRecommendationCommand.java
@@ -23,6 +23,7 @@ import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
 import org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import java.io.File;
 import java.util.HashMap;
@@ -40,9 +41,9 @@ import static org.apache.ambari.server.api.services.stackadvisor.recommendations
 public class ConfigurationDependenciesRecommendationCommand extends
     StackAdvisorCommand<RecommendationResponse> {
 
-  public ConfigurationDependenciesRecommendationCommand(File recommendationsDir, String stackAdvisorScript, int requestId,
+  public ConfigurationDependenciesRecommendationCommand(ApiVersion apiVersion, File recommendationsDir, String stackAdvisorScript, int requestId,
                                                         StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
-    super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
+    super(apiVersion, recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommand.java
index ad01b40..dd762ae 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommand.java
@@ -23,6 +23,8 @@ import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
 import org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
+import org.apache.ambari.server.api.util.ApiVersion;
+
 import static org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse.*;
 
 import java.io.File;
@@ -38,9 +40,9 @@ import java.util.Set;
 public class ConfigurationRecommendationCommand extends
     StackAdvisorCommand<RecommendationResponse> {
 
-  public ConfigurationRecommendationCommand(File recommendationsDir, String stackAdvisorScript, int requestId,
+  public ConfigurationRecommendationCommand(ApiVersion apiVersion, File recommendationsDir, String stackAdvisorScript, int requestId,
                                             StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
-    super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
+    super(apiVersion, recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationValidationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationValidationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationValidationCommand.java
index c234947..c90cc1b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationValidationCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationValidationCommand.java
@@ -25,15 +25,16 @@ import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
 import org.apache.ambari.server.api.services.stackadvisor.validations.ValidationResponse;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 /**
  * {@link StackAdvisorCommand} implementation for configuration validation.
  */
 public class ConfigurationValidationCommand extends StackAdvisorCommand<ValidationResponse> {
 
-  public ConfigurationValidationCommand(File recommendationsDir, String stackAdvisorScript,
+  public ConfigurationValidationCommand(ApiVersion apiVersion, File recommendationsDir, String stackAdvisorScript,
                                         int requestId, StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
-    super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
+    super(apiVersion, recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java
index 3e20a09..b93ea27 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java
@@ -43,6 +43,7 @@ import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorResponse;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.commons.collections.CollectionUtils;
@@ -104,8 +105,9 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend
   private final AmbariMetaInfo metaInfo;
 
   @SuppressWarnings("unchecked")
-  public StackAdvisorCommand(File recommendationsDir, String stackAdvisorScript, int requestId,
-      StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
+  public StackAdvisorCommand(ApiVersion apiVersion, File recommendationsDir, String stackAdvisorScript, int requestId,
+                             StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
+    super(apiVersion);
     this.type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
         .getActualTypeArguments()[0];
 


[05/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/databases-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/databases-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/databases-test.js
new file mode 100644
index 0000000..c3ac272
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/databases-test.js
@@ -0,0 +1,276 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+var controller;
+var store;
+
+moduleFor('controller:databases', 'DatabasesController', {
+  needs: [ 'adapter:database',
+           'service:database',
+           'service:notify',
+           'model:database' ],
+
+  setup: function () {
+    //mock getDatabases which is called on controller init
+    this.container.lookup('service:database').getDatabases = function () {
+      var defer = Ember.RSVP.defer();
+
+      defer.resolve();
+
+      return defer.promise;
+    };
+
+    //mock getDatabasesFromServer which is called by the poller
+    this.container.lookup('service:database').getDatabasesFromServer = function () {
+     var defer = Ember.RSVP.defer();
+
+     var databases = [ "database_a", "database_b"];
+
+     defer.resolve(databases);
+     return defer.promise;
+     };
+
+    store = this.container.lookup('store:main');
+    controller = this.subject();
+    controller.store = store;
+
+  },
+
+  teardown: function () {
+    Ember.run(controller, controller.destroy);
+  }
+});
+
+test('controller is initialized properly.', function () {
+  expect(5);
+
+  var controller = this.subject();
+
+  ok(controller.get('tableSearchResults'), 'table search results collection was initialized.');
+  ok(controller.get('tabs'), 'tabs collection was initialized.');
+  equal(controller.get('tabs.length'), 2, 'tabs collection contains two tabs');
+  equal(controller.get('tabs').objectAt(0).get('name'), Ember.I18n.t('titles.explorer'), 'first tab is database explorer.');
+  equal(controller.get('tabs').objectAt(1).get('name'), Ember.I18n.t('titles.results'), 'second tab is search results');
+});
+
+test('setTablePageAvailability sets canGetNextPage true if given database hasNext flag is true.', function () {
+  expect(1);
+
+  var database = Ember.Object.create( { hasNext: true } );
+
+  controller.setTablePageAvailability(database);
+
+  equal(database.get('canGetNextPage'), true);
+});
+
+test('setTablePageAvailability sets canGetNextPage true if given database has more loaded tables than the visible ones.', function () {
+  expect(1);
+
+  var database = Ember.Object.create({
+    tables: [1],
+    visibleTables: []
+  });
+
+  controller.setTablePageAvailability(database);
+
+  equal(database.get('canGetNextPage'), true);
+});
+
+test('setTablePageAvailability sets canGetNextPage falsy if given database hasNext flag is falsy and all loaded tables are visible.', function () {
+  expect(1);
+
+  var database = Ember.Object.create({
+    tables: [1],
+    visibleTables: [1]
+  });
+
+  controller.setTablePageAvailability(database);
+
+  ok(!database.get('canGetNextPage'));
+});
+
+test('setColumnPageAvailability sets canGetNextPage true if given table hasNext flag is true.', function () {
+  expect(1);
+
+  var table = Ember.Object.create( { hasNext: true } );
+
+  controller.setColumnPageAvailability(table);
+
+  equal(table.get('canGetNextPage'), true);
+});
+
+test('setColumnPageAvailability sets canGetNextPage true if given table has more loaded columns than the visible ones.', function () {
+  expect(1);
+
+  var table = Ember.Object.create({
+    columns: [1],
+    visibleColumns: []
+  });
+
+  controller.setColumnPageAvailability(table);
+
+  equal(table.get('canGetNextPage'), true);
+});
+
+test('setColumnPageAvailability sets canGetNextPage true if given database hasNext flag is falsy and all loaded columns are visible.', function () {
+  expect(1);
+
+  var table = Ember.Object.create({
+    columns: [1],
+    visibleColumns: [1]
+  });
+
+  controller.setColumnPageAvailability(table);
+
+  ok(!table.get('canGetNextPage'));
+});
+
+test('getTables sets the visibleTables as the first page of tables if they are already loaded', function () {
+  expect(2);
+
+  var database = Ember.Object.create({
+    name: 'test_db',
+    tables: [1, 2, 3]
+  });
+
+  controller.get('databases').pushObject(database);
+  controller.set('pageCount', 2);
+
+  controller.send('getTables', 'test_db');
+
+  equal(database.get('visibleTables.length'), controller.get('pageCount'), 'there are 2 visible tables out of 3.');
+  equal(database.get('canGetNextPage'), true, 'user can get next tables page.');
+});
+
+test('getColumns sets the visibleColumns as the first page of columns if they are already loaded.', function () {
+  expect(2);
+
+  var table = Ember.Object.create({
+    name: 'test_table',
+    columns: [1, 2, 3]
+  });
+
+  var database = Ember.Object.create({
+    name: 'test_db',
+    tables: [ table ],
+    visibleTables: [ table ]
+  });
+
+  controller.set('pageCount', 2);
+
+  controller.send('getColumns', 'test_table', database);
+
+  equal(table.get('visibleColumns.length'), controller.get('pageCount'), 'there are 2 visible columns out of 3.');
+  equal(table.get('canGetNextPage'), true, 'user can get next columns page.');
+});
+
+test('showMoreTables pushes more tables to visibleTables if there are still hidden tables loaded.', function () {
+  expect(2);
+
+  var database = Ember.Object.create({
+    name: 'test_db',
+    tables: [1, 2, 3],
+    visibleTables: [1]
+  });
+
+  controller.get('databases').pushObject(database);
+  controller.set('pageCount', 1);
+
+  controller.send('showMoreTables', database);
+
+  equal(database.get('visibleTables.length'), controller.get('pageCount') * 2, 'there are 2 visible tables out of 3.');
+  equal(database.get('canGetNextPage'), true, 'user can get next tables page.');
+});
+
+test('showMoreColumns pushes more columns to visibleColumns if there are still hidden columns loaded.', function () {
+  expect(2);
+
+  var table = Ember.Object.create({
+    name: 'test_table',
+    columns: [1, 2, 3],
+    visibleColumns: [1]
+  });
+
+  var database = Ember.Object.create({
+    name: 'test_db',
+    tables: [ table ],
+    visibleTables: [ table ]
+  });
+
+  controller.set('pageCount', 1);
+
+  controller.send('showMoreColumns', table, database);
+
+  equal(table.get('visibleColumns.length'), controller.get('pageCount') * 2, 'there are 2 visible columns out of 3.');
+  equal(table.get('canGetNextPage'), true, 'user can get next columns page.');
+});
+
+test('syncDatabases pushed more databases when new databases are added in the backend', function() {
+  expect(3);
+
+  var databaseA = {
+    id: "database_a",
+    name: "database_a"
+  };
+
+  Ember.run(function() {
+    store.createRecord('database', databaseA);
+    controller.syncDatabases();
+  });
+
+  var latestDbNames = store.all('database').mapBy('name');
+  equal(latestDbNames.length, 2, "There is 1 additional database added to hive");
+  equal(latestDbNames.contains("database_a"), true, "New database list should contain the old database name.");
+  equal(latestDbNames.contains("database_b"), true, "New database list should contain the new database name.");
+});
+
+test('syncDatabases removed database when old databases are removed in the backend', function() {
+  expect(4);
+
+  var latestDbNames;
+
+  var databaseA = {
+    id: "database_a",
+    name: "database_a"
+  };
+  var databaseB = {
+    id: "database_b",
+    name: "database_b"
+  };
+  var databaseC = {
+    id: "database_c",
+    name: "database_c"
+  };
+
+  Ember.run(function() {
+    store.createRecord('database', databaseA);
+    store.createRecord('database', databaseB);
+    store.createRecord('database', databaseC);
+    controller.syncDatabases();
+  });
+
+  latestDbNames = store.all('database').mapBy('name');
+  equal(latestDbNames.length, 2, "One database is removed from hive");
+  equal(latestDbNames.contains("database_a"), true, "New database list should contain the old database name.");
+  equal(latestDbNames.contains("database_b"), true, "New database list should contain the old database name.");
+  equal(latestDbNames.contains("database_c"), false, "New database list should not contain the database name removed in the backend.");
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/history-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/history-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/history-test.js
new file mode 100644
index 0000000..ab45214
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/history-test.js
@@ -0,0 +1,117 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:history', 'HistoryController', {
+  needs: [ 'service:file', 'service:job' ]
+});
+
+test('controller is initialized correctly', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  equal(component.get('columns.length'), 4, 'Columns are initialized');
+});
+
+test('date range is set correctly', function () {
+  expect(2);
+
+  var component = this.subject();
+  var min = parseInt(Date.now() / 1000) - (60 * 60 * 24 * 60);
+  var max = parseInt(Date.now() / 1000);
+
+  var history = Ember.ArrayProxy.create({ content: [
+    Ember.Object.create({
+      dateSubmittedTimestamp: min
+    }),
+    Ember.Object.create({
+      dateSubmittedTimestamp: max
+    })
+  ]});
+
+  Ember.run(function() {
+    component.set('history', history);
+  });
+
+  var dateColumn = component.get('columns').find(function (column) {
+    return column.get('caption') === 'columns.date';
+  });
+
+  equal(dateColumn.get('dateRange.min'), min, 'Min date is set correctly');
+  equal(dateColumn.get('dateRange.max'), max, 'Max date is set correctly');
+});
+
+test('interval duration is set correctly', function () {
+  expect(2);
+
+  var component = this.subject();
+
+  var history = Ember.ArrayProxy.create({ content: [
+    Ember.Object.create({
+      duration: 20
+    }),
+    Ember.Object.create({
+      duration: 300
+    })
+  ]});
+
+  Ember.run(function() {
+    component.set('history', history);
+  });
+
+  var durationColumn = component.get('columns').find(function (column) {
+    return column.get('caption') === 'columns.duration';
+  });
+
+  equal(durationColumn.get('numberRange.min'), 20, 'Min value is set correctly');
+  equal(durationColumn.get('numberRange.max'), 300, 'Max value is set correctly');
+});
+
+test('history filtering', function() {
+  expect(2);
+
+  var component = this.subject();
+
+  var history = Ember.ArrayProxy.create({
+    content: [
+      Ember.Object.create({
+        name: 'HISTORY',
+        status: 1
+      }),
+      Ember.Object.create({
+        name: '1HISTORY',
+        status: 2
+      })
+    ]
+  });
+
+  Ember.run(function() {
+    component.set('history', history);
+  });
+
+  equal(component.get('model.length'), 2, 'No filters applied we have 2 models');
+
+  Ember.run(function() {
+    component.filterBy('name', 'HISTORY', true);
+  });
+
+  equal(component.get('model.length'), 1, 'Filter by name we have 1 filtered model');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js
new file mode 100644
index 0000000..290f61e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js
@@ -0,0 +1,328 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+import constants from 'hive/utils/constants';
+
+moduleFor('controller:index', 'IndexController', {
+  needs: [
+          'controller:open-queries',
+          'controller:udfs',
+          'controller:index/history-query/logs',
+          'controller:index/history-query/results',
+          'controller:index/history-query/explain',
+          'controller:settings',
+          'controller:visual-explain',
+          'controller:tez-ui',
+          'service:job',
+          'service:file',
+          'service:database',
+          'service:notify',
+          'service:job-progress',
+          'service:session',
+          'service:settings',
+          'adapter:application',
+          'adapter:database'
+        ]
+});
+
+test('modelChanged calls update on the open-queries cotnroller.', function () {
+  expect(1);
+
+  var controller = this.subject();
+
+  controller.set('openQueries.update', function () {
+    var defer = Ember.RSVP.defer();
+
+    ok(true, 'index model has changed. update was called on open-queries controller.');
+
+    defer.resolve();
+
+    return defer.promise;
+  });
+
+  Ember.run(function () {
+    controller.set('model', Ember.Object.create());
+  });
+});
+
+test('bindQueryParams replaces param placeholder with values', function() {
+  expect(1);
+
+  var controller = this.subject();
+  var queryParams = [
+    { name: '$what', value: 'color' },
+    { name: '$where', value: 'z'}
+  ];
+
+  var query = "select $what from $where";
+  var replacedQuery = "select color from z";
+
+  Ember.run(function() {
+    controller.get('queryParams').setObjects(queryParams);
+  });
+
+  equal(controller.bindQueryParams(query), replacedQuery, 'Params replaced correctly');
+});
+
+test('bindQueryParams replaces same param multiple times', function() {
+  expect(1);
+
+  var controller = this.subject();
+  var queryParams = [
+    { name: '$what', value: 'color' },
+    { name: '$where', value: 'z'}
+  ];
+
+  var query = "select $what from $where as $what";
+  var replacedQuery = "select color from z as color";
+
+  Ember.run(function() {
+    controller.get('queryParams').setObjects(queryParams);
+  });
+
+  equal(controller.bindQueryParams(query), replacedQuery, 'Params replaced correctly');
+});
+
+test('parseQueryParams sets queryParams when query changes', function() {
+  expect(4);
+
+
+  var query = Ember.Object.create({
+    id: 1,
+    fileContent: "select $what from $where"
+  });
+  var updatedQuery = "select $what from $where and $where";
+
+  var controller = this.subject({
+    model: query
+  });
+
+  Ember.run(function() {
+    controller.set('openQueries.queryTabs', [query]);
+    controller.set('openQueries.currentQuery', query);
+  });
+
+  equal(controller.get('queryParams.length'), 2, '2 queryParams parsed');
+  equal(controller.get('queryParams').objectAt(0).name, '$what', 'First param parsed correctly');
+  equal(controller.get('queryParams').objectAt(1).name, '$where', 'Second param parsed correctly');
+
+  Ember.run(function() {
+    controller.set('openQueries.currentQuery.fileContent', updatedQuery);
+  });
+
+  equal(controller.get('queryParams.length'), 2, 'Can use same param multiple times');
+});
+
+test('canExecute return false if query is executing', function() {
+  expect(2);
+  var controller = this.subject();
+
+  Ember.run(function() {
+    controller.set('openQueries.update', function () {
+      var defer = Ember.RSVP.defer();
+      defer.resolve();
+      return defer.promise;
+    });
+
+    controller.set('model', Ember.Object.create({ 'isRunning': false }));
+    controller.set('queryParams', []);
+  });
+
+  ok(controller.get('canExecute'), 'Query is not executing => canExecute return true');
+
+  Ember.run(function() {
+    controller.set('model', Ember.Object.create({ 'isRunning': true }));
+  });
+
+  ok(!controller.get('canExecute'), 'Query is executing => canExecute return false');
+});
+
+test('canExecute return false if queryParams doesnt\'t have values', function() {
+  expect(2);
+  var controller = this.subject();
+
+  var paramsWithoutValues = [
+    { name: '$what', value: '' },
+    { name: '$where', value: '' }
+  ];
+
+  var paramsWithValues = [
+    { name: '$what', value: 'value1' },
+    { name: '$where', value: 'value2' }
+  ];
+
+  Ember.run(function() {
+    controller.set('openQueries.update', function () {
+      var defer = Ember.RSVP.defer();
+      defer.resolve();
+      return defer.promise;
+    });
+    controller.set('model', Ember.Object.create({ 'isRunning': false }));
+    controller.get('queryParams').setObjects(paramsWithoutValues);
+  });
+
+  ok(!controller.get('canExecute'), 'Params without value => canExecute return false');
+
+  Ember.run(function() {
+    controller.get('queryParams').setObjects(paramsWithValues);
+  });
+
+  ok(controller.get('canExecute'), 'Params with values => canExecute return true');
+});
+
+test('Execute EXPLAIN type query', function() {
+  expect(1);
+
+  var query = Ember.Object.create({
+    id: 1,
+    fileContent: "explain select 1" // explain type query
+  });
+
+  var controller = this.subject({
+    model: query,
+    _executeQuery: function (referer) {
+      equal(referer, constants.jobReferrer.explain, 'Explain type query successful.');
+      return {then: function() {}};
+    }
+  });
+
+  Ember.run(function() {
+      controller.set('openQueries.queryTabs', [query]);
+      controller.set('openQueries.currentQuery', query);
+      controller.send('executeQuery');
+  });
+
+});
+
+test('Execute non EXPLAIN type query', function() {
+  expect(1);
+
+  var query = Ember.Object.create({
+    id: 1,
+    fileContent: "select 1" //non explain type query
+  });
+
+  var controller = this.subject({
+    model: query,
+    _executeQuery: function (referer) {
+      equal(referer, constants.jobReferrer.job , 'non Explain type query successful.');
+      return {then: function() {}};
+    }
+  });
+
+  Ember.run(function() {
+      controller.set('openQueries.queryTabs', [query]);
+      controller.set('openQueries.currentQuery', query);
+      controller.send('executeQuery');
+  });
+
+});
+
+
+test('csvUrl returns if the current query is not a job', function() {
+  expect(1);
+  var content = Ember.Object.create({
+      constructor: {
+        typeKey: 'notJob'
+      }
+  });
+
+  var controller = this.subject({ content: content });
+  ok(!controller.get('csvUrl'), 'returns if current query is not a job');
+});
+
+test('csvUrl returns is status in not SUCCEEDED', function() {
+  expect(1);
+  var content= Ember.Object.create({
+      constructor: {
+        typeKey: 'job'
+      },
+      status: 'notSuccess'
+  });
+
+  var controller = this.subject({ content: content });
+  ok(!controller.get('csvUrl'), 'returns if current status is not success');
+});
+
+test('csvUrl return the download results as csv link', function() {
+  expect(1);
+  var content = Ember.Object.create({
+      constructor: {
+        typeKey: 'job'
+      },
+      status: 'SUCCEEDED',
+      id: 1
+  });
+
+  var controller = this.subject({ content: content });
+  ok(controller.get('csvUrl'));
+});
+
+test('donwloadMenu returns null if status is not succes and results are not visible ', function() {
+  expect(1);
+  var content = Ember.Object.create({
+      status: 'notSuccess',
+      queryProcessTabs: [{
+        path: 'index.historyQuery.results',
+        visible: false
+      }]
+  });
+
+  var controller = this.subject({ content: content });
+  ok(!controller.get('downloadMenu'), 'Returns null');
+});
+
+test('donwloadMenu returns only saveToHDFS if csvUrl is false', function() {
+  expect(1);
+  var content = Ember.Object.create({
+      constructor: {
+        typeKey: 'notjob'
+      },
+      status: 'SUCCEEDED',
+  });
+
+  var controller = this.subject({ content: content });
+  Ember.run(function() {
+    var tabs = controller.get('queryProcessTabs');
+    var results = tabs.findBy('path', 'index.historyQuery.results');
+    results.set('visible', true);
+  });
+
+  equal(controller.get('downloadMenu.length'), 1, 'Returns only saveToHDFS');
+});
+
+test('donwloadMenu returns saveToHDFS and csvUrl', function() {
+  expect(1);
+  var content = Ember.Object.create({
+      constructor: {
+        typeKey: 'job'
+      },
+      status: 'SUCCEEDED',
+  });
+
+  var controller = this.subject({ content: content });
+  Ember.run(function() {
+    var tabs = controller.get('queryProcessTabs');
+    var results = tabs.findBy('path', 'index.historyQuery.results');
+    results.set('visible', true);
+  });
+
+  equal(controller.get('downloadMenu.length'), 2, 'Returns saveToHDFS and csvUrl');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/insert-udfs-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/insert-udfs-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/insert-udfs-test.js
new file mode 100644
index 0000000..e770bdd
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/insert-udfs-test.js
@@ -0,0 +1,68 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:insert-udfs', 'InsertUdfsController', {
+  needs: 'controller:udfs'
+});
+
+test('controller is initialized correctly', function () {
+  expect(1);
+
+  var udfs = Ember.A([
+    Ember.Object.create({ fileResource: { id: 1 } }),
+    Ember.Object.create({ fileResource: { id: 1 } }),
+    Ember.Object.create({ fileResource: { id: 2 } }),
+    Ember.Object.create({ fileResource: { id: 2 } })
+  ]);
+
+  var component = this.subject();
+
+  Ember.run(function() {
+    component.set('udfs', udfs);
+  });
+
+  equal(component.get('length'), 2, 'should contain unique file resources');
+});
+
+test('controller updates on new udfs', function () {
+  expect(2);
+
+  var udfs = Ember.A([
+    Ember.Object.create({ fileResource: { id: 1 } }),
+    Ember.Object.create({ fileResource: { id: 2 } }),
+  ]);
+
+  var component = this.subject();
+
+  Ember.run(function() {
+    component.set('udfs', udfs);
+  });
+
+  equal(component.get('length'), 2, '');
+
+  var newUdf = Ember.Object.create({ isNew: true, fileResource: { id: 3 } });
+
+  Ember.run(function() {
+    component.get('udfs').pushObject(newUdf);
+  });
+
+  equal(component.get('length'), 3, '');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/messages-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/messages-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/messages-test.js
new file mode 100644
index 0000000..b0cdf16
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/messages-test.js
@@ -0,0 +1,53 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:messages', 'MessagesController', {
+});
+
+test('Controller is initialized', function() {
+  var controller = this.subject();
+
+  ok(controller, 'Controller is initialized');
+});
+
+test('Controller action', function() {
+  var controller = this.subject({
+    notifyService: Ember.Object.create({
+      removeMessage: function(message) {
+        ok(1, 'removeMessage action called');
+      },
+      removeAllMessages: function() {
+        ok(1, 'removeAllMessages action called');
+      },
+      markMessagesAsSeen: function(message) {
+        ok(1, 'markMessagesAsSeen action called');
+      }
+    })
+  });
+
+  Ember.run(function() {
+    controller.send('removeMessage');
+    controller.send('removeAllMessages');
+    controller.send('markMessagesAsSeen');
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/open-queries-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/open-queries-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/open-queries-test.js
new file mode 100644
index 0000000..c46134d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/open-queries-test.js
@@ -0,0 +1,102 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:open-queries', 'OpenQueriesController', {
+  needs: [ 'controller:index/history-query/results',
+           'controller:index/history-query/explain',
+           'controller:index',
+           'controller:settings',
+           'service:file',
+           'service:database'
+         ]
+});
+
+test('when initialized, controller sets the queryTabs.', function () {
+  expect(1);
+
+  var controller = this.subject();
+
+  ok(controller.get('queryTabs', 'queryTabs is initialized.'));
+});
+
+test('pushObject override creates a new queryFile mock and adds it to the collection if none provided.', function () {
+  expect(3);
+
+  var controller = this.subject();
+
+  var model = Ember.Object.create({
+    id: 5
+  });
+
+  controller.pushObject(null, model);
+
+  equal(controller.get('length'), 1, 'a new object was added to the open queries collection.');
+  equal(controller.objectAt(0).id, model.get('id'), 'the object id was set to the model id.');
+  equal(controller.objectAt(0).get('fileContent'), '', 'the object fileContent is initialized with empty string.');
+});
+
+test('getTabForModel retrieves the tab that has the id and the type equal to the ones of the given model.', function () {
+  expect(1);
+
+  var controller = this.subject();
+
+  var model = Ember.Object.create({
+    id: 1
+  });
+
+  controller.get('queryTabs').pushObject(Ember.Object.create({
+    id: model.get('id')
+  }));
+
+  equal(controller.getTabForModel(model), controller.get('queryTabs').objectAt(0), 'retrieves correct tab for the given model.');
+});
+
+test('getQueryForModel retrieves the query by id equality if a new record is given', function () {
+  expect(1);
+
+  var controller = this.subject();
+
+  var model = Ember.Object.create({
+    id: 1,
+    isNew: true
+  });
+
+  controller.pushObject(null, model);
+
+  equal(controller.getQueryForModel(model).get('id'), model.get('id'), 'a new record was given, the method retrieves the query by id equality');
+});
+
+test('getQueryForModel retrieves the query by record id equality with model queryFile path if a saved record is given', function () {
+  expect(1);
+
+  var controller = this.subject();
+
+  var model = Ember.Object.create({
+    id: 1,
+    queryFile: 'some/path'
+  });
+
+  controller.pushObject(Ember.Object.create({
+    id: model.get('queryFile')
+  }));
+
+  equal(controller.getQueryForModel(model).get('id'), model.get('queryFile'), 'a saved record was given, the method retrieves the query by id equality with record queryFile path.');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/queries-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/queries-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/queries-test.js
new file mode 100644
index 0000000..2578c33
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/queries-test.js
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:queries', 'QueriesController', {
+  needs: [
+    'controller:history',
+    'controller:open-queries'
+  ]
+});
+
+test('controller is initialized', function() {
+  expect(1);
+
+  var component = this.subject();
+
+  equal(component.get('columns.length'), 4, 'Columns are initialized correctly');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js
new file mode 100644
index 0000000..366d18c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js
@@ -0,0 +1,136 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:settings', 'SettingsController', {
+  needs: [
+    'controller:databases',
+    'controller:index',
+    'controller:open-queries',
+    'controller:index/history-query/results',
+    'controller:index/history-query/explain',
+    'controller:udfs',
+    'controller:index/history-query/logs',
+    'controller:visual-explain',
+    'controller:tez-ui',
+    'adapter:database',
+    'adapter:application',
+    'service:settings',
+    'service:notify',
+    'service:database',
+    'service:file',
+    'service:session',
+    'service:job',
+    'service:job-progress'
+  ]
+});
+
+test('can add a setting', function() {
+  var controller = this.subject();
+
+  ok(!controller.get('settings.length'), 'No initial settings');
+
+  Ember.run(function() {
+    controller.send('add');
+  });
+
+  equal(controller.get('settings.length'), 1, 'Can add settings');
+});
+
+test('validate', function() {
+  var predefinedSettings = [
+    {
+      name: 'some.key',
+      validate: new RegExp(/^\d+$/) // digits
+    }
+  ];
+
+  var controller = this.subject({
+    predefinedSettings: predefinedSettings
+  });
+
+  controller.set('openQueries.update', function () {
+    var defer = Ember.RSVP.defer();
+    defer.resolve();
+
+    return defer.promise;
+  });
+
+  var settings = [
+    Ember.Object.create({key: { name: 'some.key' }, value: 'value'}),
+    Ember.Object.create({key: { name: 'some.key' }, value: '123'})
+  ];
+
+  Ember.run(function() {
+    controller.set('settings', settings);
+  });
+
+  var currentSettings = controller.get('settings');
+  ok(!currentSettings.get('firstObject.valid'), "First setting doesn\' pass validataion");
+  ok(currentSettings.get('lastObject.valid'), 'Second setting passes validation');
+});
+
+test('Actions', function(assert) {
+  assert.expect(5);
+
+  var settingsService = Ember.Object.create({
+    add: function() {
+      assert.ok(true, 'add called');
+    },
+    remove: function(setting) {
+      assert.ok(setting, 'Setting param is sent');
+    },
+    createKey: function(name) {
+      assert.ok(name, 'Name param is sent');
+    },
+    removeAll: function() {
+      assert.ok(true, 'removeAll called');
+    },
+    saveDefaultSettings: function() {
+      assert.ok(true, 'saveDefaultSettings called');
+    }
+  });
+
+  var controller = this.subject();
+  controller.set('settingsService', settingsService);
+
+  Ember.run(function() {
+    controller.send('add');
+    controller.send('remove', {});
+    controller.send('addKey', {});
+    controller.send('removeAll');
+    controller.send('saveDefaultSettings');
+  });
+});
+
+
+test('Excluded settings', function(assert) {
+  var controller = this.subject();
+
+  console.log(controller.get('predefinedSettings'));
+  assert.equal(controller.get('excluded').length, 0, 'Initially there are no excluded settings');
+
+  Ember.run(function() {
+    controller.get('settings').pushObject(Ember.Object.create({ key: { name: 'hive.tez.container.size' }}));
+    controller.get('settings').pushObject(Ember.Object.create({ key: { name: 'hive.prewarm.enabled' }}));
+  });
+
+  assert.equal(controller.get('excluded').length, 2, 'Two settings are excluded');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/tez-ui-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/tez-ui-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/tez-ui-test.js
new file mode 100644
index 0000000..fdf4a89
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/tez-ui-test.js
@@ -0,0 +1,98 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import DS from 'ember-data';
+import { moduleFor, test } from 'ember-qunit';
+
+var container;
+
+moduleFor('controller:tez-ui', 'TezUIController', {
+  needs: [
+    'controller:index',
+    'service:job',
+    'service:file',
+    'controller:open-queries',
+    'controller:databases',
+    'controller:udfs',
+    'controller:index/history-query/logs',
+    'controller:index/history-query/results',
+    'controller:index/history-query/explain',
+    'controller:settings',
+    'controller:visual-explain',
+    'adapter:database',
+    'service:database',
+    'service:notify',
+    'service:job-progress',
+    'service:session',
+    'service:settings'
+  ],
+
+  setup: function() {
+    container = new Ember.Container();
+    container.register('store:main', Ember.Object.extend({
+      find: Ember.K
+    }));
+  }
+});
+
+test('controller is initialized properly.', function () {
+  expect(1);
+
+  var controller = this.subject();
+
+  ok(controller);
+});
+
+test('dagId returns false if there is  no tez view available', function() {
+  var controller = this.subject();
+
+  ok(!controller.get('dagId'), 'dagId is false without a tez view available');
+});
+
+// test('dagId returns the id if there is view available', function() {
+//   var controller = this.subject({
+//   });
+
+//   Ember.run(function() {
+//     controller.set('index.model', Ember.Object.create({
+//       id: 2,
+//       dagId: 3
+//     }));
+
+//     controller.set('isTezViewAvailable', true);
+//   });
+
+//   equal(controller.get('dagId'), 3, 'dagId is truthy');
+// });
+
+test('dagURL returns false if no dag id is available', function() {
+  var controller = this.subject();
+
+  ok(!controller.get('dagURL'), 'dagURL is false');
+});
+
+test('dagURL returns the url if dag id is available', function() {
+  var controller = this.subject({
+    tezViewURL: '1',
+    tezDagPath: '2',
+    dagId: '3'
+  });
+
+  equal(controller.get('dagURL'), '123');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/udfs-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/udfs-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/udfs-test.js
new file mode 100644
index 0000000..5bd369e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/controllers/udfs-test.js
@@ -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.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:udfs', 'UdfsController', {});
+
+test('controller is initialized', function() {
+  expect(3);
+
+  var component = this.subject();
+
+  equal(component.get('columns.length'), 2, 'Columns are initialized correctly');
+  ok(component.get('sortAscending'), 'Sort ascending is true');
+  equal(component.get('sortProperties.length'), 0, 'sortProperties is empty');
+});
+
+test('sort', function() {
+ expect(2);
+
+  var component = this.subject();
+
+  Ember.run(function () {
+    component.send('sort', 'prop');
+  });
+
+  ok(component.get('sortAscending'), 'New sort prop sortAscending is set to true');
+  equal(component.get('sortProperties').objectAt(0), "prop", 'sortProperties is set to prop');
+});
+
+test('add', function() {
+  expect(1);
+
+  var store = {
+    createRecord: function(name) {
+      ok(name, 'store.createRecord called');
+    }
+  };
+  var component = this.subject({ store: store });
+
+  Ember.run(function () {
+    component.send('add');
+  });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/helpers/path-binding-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/helpers/path-binding-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/helpers/path-binding-test.js
new file mode 100644
index 0000000..22ba58a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/helpers/path-binding-test.js
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+
+import {
+  pathBinding
+} from 'hive/helpers/path-binding';
+
+import Ember from 'ember';
+
+module('PathBindingHelper');
+
+// Replace this with your real tests.
+test('it should retrieve property value for a given object.', function() {
+  var obj = Ember.Object.extend({
+    name: 'some name'
+  }).create();
+
+  var result = pathBinding(obj, 'name');
+  equal(result, obj.get('name'));
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/services/notify-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/services/notify-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/services/notify-test.js
new file mode 100644
index 0000000..383bf31
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/services/notify-test.js
@@ -0,0 +1,155 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('service:notify', 'NotifyService');
+
+test('Service initialized correctly', function () {
+  expect(3);
+
+  var service = this.subject();
+  service.removeAllMessages();
+  service.markMessagesAsSeen();
+
+  equal(service.get('messages.length'), 0, 'No messages');
+  equal(service.get('notifications.length'), 0, 'No notifications');
+  equal(service.get('unseenMessages.length'), 0, 'No unseenMessages');
+});
+
+test('Can add notification', function() {
+  expect(3);
+  var service = this.subject();
+
+  service.add('notif', 'message', 'body');
+
+  equal(service.get('messages.length'), 1, 'one message added');
+  equal(service.get('notifications.length'), 1, 'one notifications added');
+  equal(service.get('unseenMessages.length'), 1, 'one unseenMessages added');
+});
+
+test('Can add info notification', function() {
+  expect(1);
+  var service = this.subject();
+
+  service.info('message', 'body');
+  equal(service.get('messages.lastObject.type.typeClass'), 'alert-info', 'Info notification added');
+});
+
+test('Can add warn notification', function() {
+  expect(1);
+  var service = this.subject();
+
+  service.warn('message', 'body');
+  equal(service.get('messages.lastObject.type.typeClass'), 'alert-warning', 'Warn notification added');
+});
+
+test('Can add error notification', function() {
+  expect(1);
+  var service = this.subject();
+
+  service.error('message', 'body');
+  equal(service.get('messages.lastObject.type.typeClass'), 'alert-danger', 'Error notification added');
+});
+
+test('Can add success notification', function() {
+  expect(1);
+  var service = this.subject();
+
+  service.success('message', 'body');
+  equal(service.get('messages.lastObject.type.typeClass'), 'alert-success', 'Success notification added');
+});
+
+test('Can format message body', function() {
+  expect(3);
+
+  var objectBody = {
+    k1: 'v1',
+    k2: 'v2'
+  };
+  var formatted = "\n\nk1:\nv1\n\nk2:\nv2";
+  var service = this.subject();
+
+  ok(!service.formatMessageBody(), 'Return nothing if no body is passed');
+  equal(service.formatMessageBody('some string'), 'some string', 'Return the body if it is a string');
+  equal(service.formatMessageBody(objectBody), formatted, 'Parse the keys and return a string if it is an object');
+});
+
+test('Can removeMessage', function() {
+  expect(4);
+
+  var service = this.subject();
+  var messagesCount = service.get('messages.length');
+  var notificationCount = service.get('notifications.length');
+
+  service.add('type', 'message', 'body');
+
+  equal(service.get('messages.length'), messagesCount + 1, 'Message added');
+  equal(service.get('notifications.length'), notificationCount + 1, 'Notification added');
+
+  var message = service.get('messages.lastObject');
+  service.removeMessage(message);
+
+  equal(service.get('messages.length'), messagesCount, 'Message removed');
+  equal(service.get('notifications.length'), notificationCount, 'Notification removed');
+});
+
+test('Can removeNotification', function() {
+  expect(2);
+
+  var service = this.subject();
+  var notificationCount = service.get('notifications.length');
+
+  service.add('type', 'message', 'body');
+
+  equal(service.get('notifications.length'), notificationCount + 1, 'Notification added');
+
+  var notification = service.get('notifications.lastObject');
+  service.removeNotification(notification);
+
+  equal(service.get('notifications.length'), notificationCount, 'Notification removed');
+});
+
+test('Can removeAllMessages', function() {
+  expect(2);
+
+  var service = this.subject();
+
+  service.add('type', 'message', 'body');
+  service.add('type', 'message', 'body');
+  service.add('type', 'message', 'body');
+
+  ok(service.get('messages.length'), 'Messages are present');
+  service.removeAllMessages();
+  equal(service.get('messages.length'), 0, 'No messages found');
+});
+
+test('Can markMessagesAsSeen', function() {
+  expect(2);
+
+  var service = this.subject();
+
+  service.add('type', 'message', 'body');
+  service.add('type', 'message', 'body');
+  service.add('type', 'message', 'body');
+
+  ok(service.get('unseenMessages.length'), 'There are unseen messages');
+  service.markMessagesAsSeen();
+  equal(service.get('unseenMessages.length'), 0, 'No unseen messages');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/services/settings-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/services/settings-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/services/settings-test.js
new file mode 100644
index 0000000..cb99882
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/services/settings-test.js
@@ -0,0 +1,155 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('service:settings', 'SettingsService');
+
+test('Init', function(assert) {
+  var service = this.subject();
+  assert.ok(service);
+});
+
+test('Can create a setting object', function(assert) {
+  assert.expect(2);
+
+  var service = this.subject();
+
+  var setting = service._createSetting('sName', 'sValue');
+
+  assert.equal(setting.get('key.name'), 'sName', 'Settign has the correct name');
+  assert.equal(setting.get('value'), 'sValue', 'Settign has the correct value');
+
+  service.removeAll();
+});
+
+test('Can create default settings', function(assert) {
+  assert.expect(2);
+
+  var service = this.subject();
+
+  var settings = {
+    'sName1': 'sValue1',
+    'sName2': 'sValue2',
+    'sName3': 'sValue3'
+  };
+
+  service._createDefaultSettings();
+
+  assert.equal(service.get('settings.length'), 0, '0 settings created');
+
+  service._createDefaultSettings(settings);
+
+  assert.equal(service.get('settings.length'), 3, '3 settings created');
+
+  service.removeAll();
+});
+
+test('Can add a setting', function(assert) {
+  assert.expect(2);
+
+  var service = this.subject();
+  assert.equal(service.get('settings.length'), 0, 'No settings');
+  service.add();
+  service.add();
+  assert.equal(service.get('settings.length'), 2, '2 settings added');
+
+  service.removeAll();
+});
+
+test('Can remove a setting', function(assert) {
+  assert.expect(2);
+
+  var service = this.subject();
+
+  service.add();
+  service.add();
+
+  assert.equal(service.get('settings.length'), 2, '2 settings added');
+  var firstSetting = service.get('settings.firstObject');
+  service.remove(firstSetting);
+  assert.equal(service.get('settings.length'), 1, 'Setting removed');
+
+  service.removeAll();
+});
+
+test('Can create key', function(assert) {
+  assert.expect(2);
+  var service = this.subject();
+
+  assert.ok(!service.get('predefinedSettings').findBy('name', 'new.key.name'), 'Key doesn\'t exist');
+
+  var setting = service._createSetting();
+  setting.set('key', null);
+  service.get('settings').pushObject(setting);
+  service.createKey('new.key.name');
+
+  assert.ok(service.get('predefinedSettings').findBy('name', 'new.key.name'), 'Key created');
+
+  service.removeAll();
+});
+
+test('Can get settings string', function(assert) {
+  var service = this.subject();
+
+  var noSettings = service.getSettings();
+  assert.equal(noSettings, "", 'An empty string is returned if there are no settings');
+
+  var settings = {
+    'sName1': 'sValue1',
+    'sName2': 'sValue2'
+  };
+
+  service._createDefaultSettings(settings);
+
+  var expectedWithSettings = "set sName1=sValue1;\nset sName2=sValue2;\n--Global Settings--\n\n";
+  var withSettings = service.getSettings();
+
+  assert.equal(withSettings, expectedWithSettings, 'Returns correct string');
+});
+
+test('It can parse global settings', function(assert) {
+  var service = this.subject();
+
+  assert.ok(!service.parseGlobalSettings(), 'It returns if query or model is not passed');
+
+  var settings = {
+    'sName1': 'sValue1',
+    'sName2': 'sValue2'
+  };
+
+
+  var globalSettingsString = "set sName1=sValue1;\nset sName2=sValue2;\n--Global Settings--\n\n";
+
+  var model = Ember.Object.create({
+    globalSettings: globalSettingsString
+  });
+
+  var query = Ember.Object.create({
+    fileContent: globalSettingsString + "{{match}}"
+  });
+
+  assert.ok(!service.parseGlobalSettings(query, model), 'It returns if current settings don\'t match models global settings');
+
+  service._createDefaultSettings(settings);
+
+  service.parseGlobalSettings(query, model);
+
+  assert.equal(query.get('fileContent'), "{{match}}", 'It parsed global settings');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/views/visual-explain-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/views/visual-explain-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/views/visual-explain-test.js
new file mode 100644
index 0000000..2fa23df
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/views/visual-explain-test.js
@@ -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.
+ */
+
+import {
+  moduleFor,
+  test
+} from 'ember-qunit';
+
+var view;
+
+moduleFor('view:visual-explain', 'VisualExplainView', {
+  setup: function() {
+    var controller = Ember.Controller.extend({}).create();
+
+    view = this.subject({
+      controller: controller
+    });
+
+    Ember.run(function() {
+      view.appendTo('#ember-testing');
+    });
+  },
+
+  teardown: function() {
+    Ember.run(view, view.destroy);
+  },
+});
+
+//select count (*) from power
+var selectCountJson = {"STAGE PLANS":{"Stage-1":{"Tez":{"DagName:":"hive_20150608120000_b930a285-dc6a-49b7-86b6-8bee5ecdeacd:96","Vertices:":{"Reducer 2":{"Reduce Operator Tree:":{"Group By Operator":{"mode:":"mergepartial","aggregations:":["count(VALUE._col0)"],"outputColumnNames:":["_col0"],"children":{"Select Operator":{"expressions:":"_col0 (type: bigint)","outputColumnNames:":["_col0"],"children":{"File Output Operator":{"Statistics:":"Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: COMPLETE","compressed:":"false","table:":{"serde:":"org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe","input format:":"org.apache.hadoop.mapred.TextInputFormat","output format:":"org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat"}}},"Statistics:":"Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: COMPLETE"}},"Statistics:":"Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: COMPLETE"}}},"Map 1":{"Map Operator Tree:":[{"TableScan":{"alias:":"power","childre
 n":{"Select Operator":{"children":{"Group By Operator":{"mode:":"hash","aggregations:":["count()"],"outputColumnNames:":["_col0"],"children":{"Reduce Output Operator":{"sort order:":"","value expressions:":"_col0 (type: bigint)","Statistics:":"Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: COMPLETE"}},"Statistics:":"Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: COMPLETE"}},"Statistics:":"Num rows: 0 Data size: 132960632 Basic stats: PARTIAL Column stats: COMPLETE"}},"Statistics:":"Num rows: 0 Data size: 132960632 Basic stats: PARTIAL Column stats: COMPLETE"}}]}},"Edges:":{"Reducer 2":{"parent":"Map 1","type":"SIMPLE_EDGE"}}}},"Stage-0":{"Fetch Operator":{"limit:":"-1","Processor Tree:":{"ListSink":{}}}}},"STAGE DEPENDENCIES":{"Stage-1":{"ROOT STAGE":"TRUE"},"Stage-0":{"DEPENDENT STAGES":"Stage-1"}}};
+
+//select power.adate, power.atime from power join power2 on power.adate = power2.adate
+var joinJson = {"STAGE PLANS":{"Stage-1":{"Tez":{"DagName:":"hive_20150608124141_acde7f09-6b72-4ad4-88b0-807d499724eb:107","Vertices:":{"Reducer 2":{"Reduce Operator Tree:":{"Merge Join Operator":{"outputColumnNames:":["_col0","_col1"],"children":{"Select Operator":{"expressions:":"_col0 (type: string), _col1 (type: string)","outputColumnNames:":["_col0","_col1"],"children":{"File Output Operator":{"Statistics:":"Num rows: 731283 Data size: 73128349 Basic stats: COMPLETE Column stats: NONE","compressed:":"false","table:":{"serde:":"org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe","input format:":"org.apache.hadoop.mapred.TextInputFormat","output format:":"org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat"}}},"Statistics:":"Num rows: 731283 Data size: 73128349 Basic stats: COMPLETE Column stats: NONE"}},"Statistics:":"Num rows: 731283 Data size: 73128349 Basic stats: COMPLETE Column stats: NONE","condition map:":[{"":"Inner Join 0 to 1"}],"condition expressions:":{"1":"",
 "0":"{KEY.reducesinkkey0} {VALUE._col0}"}}}},"Map 1":{"Map Operator Tree:":[{"TableScan":{"filterExpr:":"adate is not null (type: boolean)","alias:":"power2","children":{"Filter Operator":{"predicate:":"adate is not null (type: boolean)","children":{"Reduce Output Operator":{"Map-reduce partition columns:":"adate (type: string)","sort order:":"+","Statistics:":"Num rows: 664803 Data size: 66480316 Basic stats: COMPLETE Column stats: NONE","key expressions:":"adate (type: string)"}},"Statistics:":"Num rows: 664803 Data size: 66480316 Basic stats: COMPLETE Column stats: NONE"}},"Statistics:":"Num rows: 1329606 Data size: 132960632 Basic stats: COMPLETE Column stats: NONE"}}]},"Map 3":{"Map Operator Tree:":[{"TableScan":{"filterExpr:":"adate is not null (type: boolean)","alias:":"power","children":{"Filter Operator":{"predicate:":"adate is not null (type: boolean)","children":{"Reduce Output Operator":{"Map-reduce partition columns:":"adate (type: string)","sort order:":"+","value expr
 essions:":"atime (type: string)","Statistics:":"Num rows: 332402 Data size: 66480416 Basic stats: COMPLETE Column stats: NONE","key expressions:":"adate (type: string)"}},"Statistics:":"Num rows: 332402 Data size: 66480416 Basic stats: COMPLETE Column stats: NONE"}},"Statistics:":"Num rows: 664803 Data size: 132960632 Basic stats: COMPLETE Column stats: NONE"}}]}},"Edges:":{"Reducer 2":[{"parent":"Map 1","type":"SIMPLE_EDGE"},{"parent":"Map 3","type":"SIMPLE_EDGE"}]}}},"Stage-0":{"Fetch Operator":{"limit:":"-1","Processor Tree:":{"ListSink":{}}}}},"STAGE DEPENDENCIES":{"Stage-1":{"ROOT STAGE":"TRUE"},"Stage-0":{"DEPENDENT STAGES":"Stage-1"}}};
+
+// Replace this with your real tests.
+test('it renders dag when controller.json changes.', function (assert) {
+  assert.expect(1);
+
+  view.renderDag = function () {
+    assert.ok(true, 'dag rendering has been called on json set.');
+  };
+
+  view.set('controller.json', selectCountJson);
+});
+
+test('renderDag generates correct number of nodes and edges.', function (assert) {
+  assert.expect(4);
+
+  Ember.run(function () {
+    view.set('controller.json', selectCountJson);
+
+    assert.equal(view.get('graph').nodes().length, 4);
+    assert.equal(view.get('graph').edges().length, 3);
+
+    view.set('controller.json', joinJson);
+
+    assert.equal(view.get('graph').nodes().length, 7);
+    assert.equal(view.get('graph').edges().length, 6);
+  });
+});
+
+test('progress gets updated for each node.', function (assert) {
+  expect(2);
+
+  Ember.run(function () {
+    view.set('controller.json', selectCountJson);
+
+    var targetNode;
+    var verticesGroups = view.get('verticesGroups');
+
+    verticesGroups.some(function (verticesGroup) {
+      var node = verticesGroup.contents.findBy('label', 'Map 1');
+
+      if (node) {
+        targetNode = node;
+        return true;
+      }
+    });
+
+    assert.equal(targetNode.get('progress'), undefined, 'initial progress is falsy.');
+
+    view.set('controller.verticesProgress', [
+      Ember.Object.create({
+        name: 'Map 1',
+        value: 1
+      })
+    ]);
+
+    assert.equal(targetNode.get('progress'), 1, 'progress gets updated to given value.');
+  });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/vendor/.gitkeep
new file mode 100644
index 0000000..e69de29


[26/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/componentsMap.dat
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/componentsMap.dat b/ambari-server/src/main/resources/componentsMap.dat
new file mode 100644
index 0000000..01bf634
--- /dev/null
+++ b/ambari-server/src/main/resources/componentsMap.dat
@@ -0,0 +1,12 @@
+ZOOKEEPER_SERVER=ZK
+HBASE_MASTER=HBASEMASTER
+HBASE_REGIONSERVER=REGIONSERVER
+LOGSEARCH_SOLR=SOLR
+LOGSEARCH_SERVER=UI
+KAFKA_BROKER=KAFKABROKER
+STORM_UI_SERVER=STORMUI
+NIMBUS=NIMBUS
+SUPERVISOR=SUPERVISOR
+NIFI_MASTER=NIFI
+TRANSACTIONMONITORUI=TRANSACTIONMONITORUI
+COMETD=COMETD

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/key_properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/key_properties.json b/ambari-server/src/main/resources/key_properties.json
index 8069349..b11870b 100644
--- a/ambari-server/src/main/resources/key_properties.json
+++ b/ambari-server/src/main/resources/key_properties.json
@@ -2,6 +2,10 @@
   "Cluster": {
     "Cluster": "Clusters/cluster_name"
   },
+  "ServiceGroup": {
+    "Cluster": "ServiceGroupInfo/cluster_name",
+    "ServiceGroup": "ServiceGroupInfo/service_group_name"
+  },
   "Service": {
     "Cluster": "ServiceInfo/cluster_name",
     "Service": "ServiceInfo/service_name"
@@ -19,6 +23,7 @@
   "HostComponent": {
     "Cluster": "HostRoles/cluster_name",
     "Host": "HostRoles/host_name",
+    "Service": "HostRoles/service_name",
     "HostComponent": "HostRoles/component_name",
     "Component": "HostRoles/component_name"
   },

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json
index eac0dbd..3a8e914 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -12,9 +12,27 @@
         "Clusters/health_report",
         "_"
     ],
+    "ServiceGroup":[
+        "ServiceGroupInfo/cluster_name",
+        "ServiceGroupInfo/service_group_name",
+        "ServiceGroupInfo/service_group_display_name",
+        "ServiceGroupInfo/service_group_type",
+        "ServiceGroupInfo/assembly_file",
+        "ServiceGroupInfo/desired_state",
+        "ServiceGroupInfo/current_state",
+        "ServiceGroupInfo/application_id",
+        "ServiceGroupInfo/lifetime",
+        "ServiceGroupInfo/quicklinks",
+        "ServiceGroupInfo/containers",
+        "ServiceGroupInfo/number_of_containers",
+        "ServiceGroupInfo/expected_number_of_containers",
+        "_"
+    ],
     "Service":[
-        "ServiceInfo/service_name",
         "ServiceInfo/cluster_name",
+        "ServiceInfo/service_name",
+        "ServiceInfo/stack_service_name",
+        "ServiceInfo/service_group_name",
         "ServiceInfo/state",
         "ServiceInfo/maintenance_state",
         "Services/description",
@@ -60,6 +78,7 @@
         "ServiceComponents/display_name",
         "ServiceComponents/description",
         "ServiceComponentInfo/category",
+        "ServiceComponentInfo/desired_count",
         "ServiceComponentInfo/total_count",
         "ServiceComponentInfo/started_count",
         "ServiceComponentInfo/installed_count",
@@ -71,6 +90,8 @@
         "HostRoles/role_id",
         "HostRoles/cluster_name",
         "HostRoles/host_name",
+        "HostRoles/bare_host_name",
+        "HostRoles/comntainer_name",
         "HostRoles/component_name",
         "HostRoles/display_name",
         "HostRoles/state",

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/stacks/HDP/2.4/services/CFMON/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.4/services/CFMON/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.4/services/CFMON/metainfo.xml
new file mode 100644
index 0000000..1dc81ef
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.4/services/CFMON/metainfo.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!--
+   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.
+-->
+<metainfo>
+<schemaVersion>2.0</schemaVersion>
+    <services>
+        <service>
+            <name>CFMON</name>
+            <displayName>CF Monitor</displayName>
+            <comment>A New Credit Fraud Monitoring Service</comment>
+            <version>1.0.0</version>
+            <components>
+                 <component>
+                     <name>TRANSACTIONMONITORUI</name>
+                     <displayName>Transation Monitoring UI</displayName>
+                     <category>MASTER</category>
+                     <cardinality>1</cardinality>
+                 </component>
+                 <component>
+                     <name>COMETD</name>
+                     <displayName>CometD Server</displayName>
+                     <category>MASTER</category>
+                     <cardinality>1</cardinality>
+                 </component>
+            </components>
+        </service>
+    </services>
+</metainfo>
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/stacks/HDP/2.4/services/NIFI/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.4/services/NIFI/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.4/services/NIFI/metainfo.xml
new file mode 100755
index 0000000..35dafe3
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.4/services/NIFI/metainfo.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+   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.
+-->
+<metainfo>
+    <schemaVersion>2.0</schemaVersion>
+    <services>
+        <service>
+            <name>NIFI</name>
+            <displayName>NiFi</displayName>
+            <comment>Apache NiFi is an easy to use, powerful, and reliable system to process and distribute data.</comment>
+            <version>0.6.0.2.4</version>
+            <components>
+                <component>
+                  <name>NIFI_MASTER</name>
+                  <displayName>NiFi</displayName>
+                  <category>MASTER</category>
+                  <cardinality>1+</cardinality>
+                  <timelineAppid>NIFI</timelineAppid>
+                </component>                       
+            </components>
+        </service>
+    </services>
+</metainfo>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/agent/HeartbeatProcessorTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/agent/HeartbeatProcessorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/agent/HeartbeatProcessorTest.java
index bdbb9ab..f9908a0 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/agent/HeartbeatProcessorTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/agent/HeartbeatProcessorTest.java
@@ -149,7 +149,7 @@ public class HeartbeatProcessorTest {
   @SuppressWarnings("unchecked")
   public void testHeartbeatWithConfigs() throws Exception {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -219,7 +219,7 @@ public class HeartbeatProcessorTest {
   @SuppressWarnings("unchecked")
   public void testRestartRequiredAfterInstallClient() throws Exception {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(HDFS_CLIENT).persist();
     hdfs.getServiceComponent(HDFS_CLIENT).addServiceComponentHost(DummyHostname1).persist();
@@ -285,7 +285,7 @@ public class HeartbeatProcessorTest {
   @SuppressWarnings("unchecked")
   public void testHeartbeatCustomCommandWithConfigs() throws Exception {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -370,7 +370,7 @@ public class HeartbeatProcessorTest {
   @SuppressWarnings("unchecked")
   public void testHeartbeatCustomStartStop() throws Exception {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -455,7 +455,7 @@ public class HeartbeatProcessorTest {
   @SuppressWarnings("unchecked")
   public void testStatusHeartbeat() throws Exception {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -587,7 +587,7 @@ public class HeartbeatProcessorTest {
   public void testCommandReportOnHeartbeatUpdatedState()
       throws AmbariException, InvalidStateTransitionException {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -707,7 +707,7 @@ public class HeartbeatProcessorTest {
   @SuppressWarnings("unchecked")
   public void testUpgradeSpecificHandling() throws AmbariException, InvalidStateTransitionException {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -802,7 +802,7 @@ public class HeartbeatProcessorTest {
   @SuppressWarnings("unchecked")
   public void testCommandStatusProcesses() throws Exception {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -884,7 +884,7 @@ public class HeartbeatProcessorTest {
   @SuppressWarnings("unchecked")
   public void testComponentUpgradeCompleteReport() throws AmbariException, InvalidStateTransitionException {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -969,7 +969,7 @@ public class HeartbeatProcessorTest {
   @SuppressWarnings("unchecked")
   public void testComponentUpgradeFailReport() throws AmbariException, InvalidStateTransitionException {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -1090,7 +1090,7 @@ public class HeartbeatProcessorTest {
   @SuppressWarnings("unchecked")
   public void testComponentUpgradeInProgressReport() throws AmbariException, InvalidStateTransitionException {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -1295,7 +1295,7 @@ public class HeartbeatProcessorTest {
   @SuppressWarnings("unchecked")
   public void testComponentInProgressStatusSafeAfterStatusReport() throws Exception {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java b/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java
index 17c5513..8259fd8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java
@@ -221,7 +221,7 @@ public class TestHeartbeatHandler {
   @SuppressWarnings("unchecked")
   public void testStatusHeartbeatWithAnnotation() throws Exception {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.addServiceComponent(NAMENODE).persist();
@@ -273,7 +273,7 @@ public class TestHeartbeatHandler {
   @SuppressWarnings("unchecked")
   public void testLiveStatusUpdateAfterStopFailed() throws Exception {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).
@@ -385,7 +385,7 @@ public class TestHeartbeatHandler {
     HeartBeatHandler handler = new HeartBeatHandler(fsm, new ActionQueue(), am,
                                                     injector);
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
 
     hdfs.addServiceComponent(DATANODE).setRecoveryEnabled(true);
@@ -449,7 +449,7 @@ public class TestHeartbeatHandler {
     HeartBeatHandler handler = new HeartBeatHandler(fsm, new ActionQueue(), am,
             injector);
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
 
     /**
@@ -784,7 +784,7 @@ public class TestHeartbeatHandler {
   @SuppressWarnings("unchecked")
   public void testTaskInProgressHandling() throws AmbariException, InvalidStateTransitionException {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -842,7 +842,7 @@ public class TestHeartbeatHandler {
   @SuppressWarnings("unchecked")
   public void testOPFailedEventForAbortedTask() throws AmbariException, InvalidStateTransitionException {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -917,7 +917,7 @@ public class TestHeartbeatHandler {
   @SuppressWarnings("unchecked")
   public void testStatusHeartbeatWithVersion() throws Exception {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -995,7 +995,7 @@ public class TestHeartbeatHandler {
 
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
     Host hostObject = clusters.getHost(DummyHostname1);
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -1077,7 +1077,7 @@ public class TestHeartbeatHandler {
 
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
     Host hostObject = clusters.getHost(DummyHostname1);
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -1411,7 +1411,7 @@ public class TestHeartbeatHandler {
   @SuppressWarnings("unchecked")
   public void testCommandStatusProcesses_empty() throws Exception {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(DATANODE).persist();
     hdfs.getServiceComponent(DATANODE).addServiceComponentHost(DummyHostname1).persist();
@@ -1548,7 +1548,7 @@ public class TestHeartbeatHandler {
     hlp.put("custom_command", "REMOVE_KEYTAB");
     executionCommand.setHostLevelParams(hlp);
 
-    Map<String, String> commandparams = new HashMap<String, String>();
+    Map<String, String> commandparams = new HashMap<>();
     commandparams.put(KerberosServerAction.AUTHENTICATED_USER_NAME, "admin");
     commandparams.put(KerberosServerAction.DATA_DIRECTORY, createTestKeytabData().getAbsolutePath());
     executionCommand.setCommandParams(commandparams);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatMonitor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatMonitor.java b/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatMonitor.java
index a5396d8..29d6564 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatMonitor.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatMonitor.java
@@ -133,7 +133,7 @@ public class TestHeartbeatMonitor {
 
 
     clusters.mapHostsToCluster(hostNames, clusterName);
-    Service hdfs = cluster.addService(serviceName);
+    Service hdfs = cluster.addService(serviceName, serviceName, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(Role.DATANODE.name()).persist();
     hdfs.getServiceComponent(Role.DATANODE.name()).addServiceComponentHost(hostname1).persist();
@@ -222,7 +222,7 @@ public class TestHeartbeatMonitor {
 
 
     clusters.mapHostsToCluster(hostNames, clusterName);
-    Service hdfs = cluster.addService(serviceName);
+    Service hdfs = cluster.addService(serviceName, serviceName, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(Role.DATANODE.name()).persist();
     hdfs.getServiceComponent(Role.DATANODE.name()).addServiceComponentHost
@@ -328,7 +328,7 @@ public class TestHeartbeatMonitor {
 
     clusters.mapHostsToCluster(hostNames, clusterName);
 
-    Service hdfs = cluster.addService(serviceName);
+    Service hdfs = cluster.addService(serviceName, serviceName, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(Role.DATANODE.name()).persist();
     hdfs.getServiceComponent(Role.DATANODE.name()).addServiceComponentHost(hostname1).persist();
@@ -446,7 +446,7 @@ public class TestHeartbeatMonitor {
 
     clusters.mapHostsToCluster(hostNames, clusterName);
 
-    Service hdfs = cluster.addService(serviceName);
+    Service hdfs = cluster.addService(serviceName, serviceName, "CORE");
     hdfs.persist();
     hdfs.addServiceComponent(Role.DATANODE.name()).persist();
     hdfs.getServiceComponent(Role.DATANODE.name()).addServiceComponentHost(hostname1).persist();
@@ -568,7 +568,7 @@ public class TestHeartbeatMonitor {
 
     clusters.mapHostsToCluster(hostNames, clusterName);
 
-    Service hdfs = cluster.addService(serviceName);
+    Service hdfs = cluster.addService(serviceName, serviceName, "CORE");
     hdfs.persist();
 
     hdfs.addServiceComponent(Role.DATANODE.name()).persist();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActionServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActionServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActionServiceTest.java
index ee85e8d..cf74b73 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActionServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActionServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -76,6 +77,7 @@ public class ActionServiceTest extends BaseServiceTest {
     private String m_actionName;
 
     private TestActionDefinitionService(String actionName) {
+      super(ApiVersion.v1);
       m_actionName = actionName;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActiveWidgetLayoutServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActiveWidgetLayoutServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActiveWidgetLayoutServiceTest.java
index c459f7c..b35c395 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActiveWidgetLayoutServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ActiveWidgetLayoutServiceTest.java
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.core.HttpHeaders;
@@ -47,7 +48,7 @@ public class ActiveWidgetLayoutServiceTest {
 
   private class TestActiveWidgetLayoutService extends ActiveWidgetLayoutService {
     public TestActiveWidgetLayoutService(String username) {
-      super(username);
+      super(ApiVersion.v1, username);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
index e5bb7ca..8747eab 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
@@ -1859,7 +1859,7 @@ public class AmbariMetaInfoTest {
     cluster.setDesiredStackVersion(
         new StackId(STACK_NAME_HDP, "2.0.6"));
 
-    cluster.addService("HDFS");
+    cluster.addService("HDFS", "HDFS", "CORE");
 
     metaInfo.reconcileAlertDefinitions(clusters);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/BlueprintServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/BlueprintServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/BlueprintServiceTest.java
index 2b368cb..e73cc2e 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/BlueprintServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/BlueprintServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -77,7 +78,8 @@ public class BlueprintServiceTest extends BaseServiceTest {
     private String m_blueprintId;
 
     private TestBlueprintService(String blueprintId) {
-      m_blueprintId = blueprintId;
+      super(ApiVersion.v1);
+       m_blueprintId = blueprintId;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterKerberosDescriptorServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterKerberosDescriptorServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterKerberosDescriptorServiceTest.java
index bc96ac9..93ca7e1 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterKerberosDescriptorServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterKerberosDescriptorServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
@@ -64,7 +65,7 @@ public class ClusterKerberosDescriptorServiceTest extends BaseServiceTest {
     private String type;
 
     private TestService(String type) {
-      super("C1");
+      super(ApiVersion.v1, "C1");
       this.type = type;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterPrivilegeServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterPrivilegeServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterPrivilegeServiceTest.java
index d321b15..eaa2642 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterPrivilegeServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterPrivilegeServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -68,7 +69,7 @@ public class ClusterPrivilegeServiceTest extends BaseServiceTest {
   private class TestClusterPrivilegeService extends ClusterPrivilegeService {
 
     private TestClusterPrivilegeService(String clusterName) {
-      super(clusterName);
+      super(ApiVersion.v1, clusterName);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterServiceTest.java
index c36f5fe..d0d3470 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.cluster.ClustersImpl;
 
@@ -128,7 +129,7 @@ public class ClusterServiceTest extends BaseServiceTest {
     private String m_clusterId;
 
     private TestClusterService(Clusters clusters, String clusterId) {
-      super(clusters);
+      super(ApiVersion.v1, clusters);
       m_clusterId = clusterId;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterStackVersionServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterStackVersionServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterStackVersionServiceTest.java
index 19d8d41..e32e63d 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterStackVersionServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterStackVersionServiceTest.java
@@ -22,6 +22,7 @@ import junit.framework.TestCase;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource.Type;
 import org.easymock.EasyMock;
 import org.junit.Test;
@@ -71,7 +72,7 @@ public class ClusterStackVersionServiceTest extends BaseServiceTest {
 
   private class TestClusterStackVersionService extends ClusterStackVersionService {
     public TestClusterStackVersionService(String clusterName) {
-      super(clusterName);
+      super(ApiVersion.v1, clusterName);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ComponentServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ComponentServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ComponentServiceTest.java
index dc57a5b..645e681 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ComponentServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ComponentServiceTest.java
@@ -23,6 +23,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -92,7 +93,7 @@ public class ComponentServiceTest extends BaseServiceTest {
     private String m_componentId;
 
     private TestComponentService(String clusterId, String serviceId, String componentId) {
-      super(clusterId, serviceId);
+      super(ApiVersion.v1, clusterId, serviceId);
       m_clusterId = clusterId;
       m_serviceId = serviceId;
       m_componentId = componentId;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigGroupServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigGroupServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigGroupServiceTest.java
index 22694f6..44eac80 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigGroupServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigGroupServiceTest.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -84,7 +85,7 @@ public class ConfigGroupServiceTest extends BaseServiceTest {
     private String m_groupId;
 
     public TestConfigGroupService(String m_clusterName, String groupId) {
-      super(m_clusterName);
+      super(ApiVersion.v1, m_clusterName);
       this.m_clusterName = m_clusterName;
       this.m_groupId = groupId;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigurationServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigurationServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigurationServiceTest.java
index 7ad3e3a..92326be 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigurationServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ConfigurationServiceTest.java
@@ -24,6 +24,7 @@ import javax.ws.rs.core.*;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import java.lang.reflect.Method;
 import java.util.ArrayList;
@@ -55,7 +56,7 @@ public class ConfigurationServiceTest extends BaseServiceTest {
     private String m_clusterId;
 
     private TestConfigurationService(String clusterId) {
-      super(clusterId);
+      super(ApiVersion.v1, clusterId);
       m_clusterId = clusterId;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/CredentialServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/CredentialServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/CredentialServiceTest.java
index 3d218fb..63e9522 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/CredentialServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/CredentialServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -71,7 +72,7 @@ public class CredentialServiceTest extends BaseServiceTest {
     private String alias;
 
     private TestCredentialService(String alias) {
-      super("C1");
+      super(ApiVersion.v1, "C1");
       this.alias = alias;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/FeedServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/FeedServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/FeedServiceTest.java
index 332e55c..b2e2415 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/FeedServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/FeedServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -79,6 +80,7 @@ public class FeedServiceTest extends BaseServiceTest {
     private String m_feedId;
 
     private TestFeedService(String feedId) {
+      super(ApiVersion.v1);
       m_feedId = feedId;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/GroupPrivilegeServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/GroupPrivilegeServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/GroupPrivilegeServiceTest.java
index 7d2188f..6fabd05 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/GroupPrivilegeServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/GroupPrivilegeServiceTest.java
@@ -22,6 +22,7 @@ import junit.framework.Assert;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource.Type;
 import org.easymock.EasyMock;
 import org.junit.Test;
@@ -83,7 +84,7 @@ public class GroupPrivilegeServiceTest extends BaseServiceTest {
   private class TestGroupPrivilegeService extends GroupPrivilegeService {
 
     public TestGroupPrivilegeService() {
-      super("group");
+      super(ApiVersion.v1, "group");
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/GroupServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/GroupServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/GroupServiceTest.java
index fdf740e..3f1d2de 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/GroupServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/GroupServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource.Type;
 
 import javax.ws.rs.core.HttpHeaders;
@@ -78,6 +79,10 @@ public class GroupServiceTest extends BaseServiceTest {
   }
 
   private class TestGroupService extends GroupService {
+    public TestGroupService() {
+      super(ApiVersion.v1);
+    }
+
     @Override
     protected ResourceInstance createResource(Type type, Map<Type, String> mapIds) {
       return getTestResource();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostComponentServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostComponentServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostComponentServiceTest.java
index 86a2d38..d442f68 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostComponentServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostComponentServiceTest.java
@@ -22,6 +22,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -91,7 +92,7 @@ public class HostComponentServiceTest extends BaseServiceTest {
     private String m_hostComponentId;
 
     private TestHostComponentService(String clusterId, String hostId, String hostComponentId) {
-      super(clusterId, hostId);
+      super(ApiVersion.v1, clusterId, hostId);
       m_clusterId = clusterId;
       m_hostId = hostId;
       m_hostComponentId = hostComponentId;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostKerberosIdentityServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostKerberosIdentityServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostKerberosIdentityServiceTest.java
index 012272c..8006702 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostKerberosIdentityServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostKerberosIdentityServiceTest.java
@@ -23,6 +23,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -61,7 +62,7 @@ public class HostKerberosIdentityServiceTest extends BaseServiceTest {
     private String identityId;
 
     private TestHostKerberosIdentityService(String clusterId, String hostId, String identityId) {
-      super(clusterId, hostId);
+      super(ApiVersion.v1, clusterId, hostId);
       this.clusterId = clusterId;
       this.hostId = hostId;
       this.identityId = identityId;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostServiceTest.java
index b66ad9d..c6e131f 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostServiceTest.java
@@ -22,6 +22,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -90,7 +91,7 @@ public class HostServiceTest extends BaseServiceTest {
     private String m_hostId;
 
     private TestHostService(String clusterId, String hostId) {
-      super(clusterId);
+      super(ApiVersion.v1, clusterId);
       m_clusterId = clusterId;
       m_hostId = hostId;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostStackVersionServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostStackVersionServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostStackVersionServiceTest.java
index 2ee1374..e507c54 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostStackVersionServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/HostStackVersionServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource.Type;
 
 import javax.ws.rs.core.HttpHeaders;
@@ -60,7 +61,7 @@ public class HostStackVersionServiceTest extends BaseServiceTest {
 
   private class TestHostStackVersionService extends HostStackVersionService {
     public TestHostStackVersionService(String hostName, String clusterName) {
-      super(hostName, clusterName);
+      super(ApiVersion.v1, hostName, clusterName);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/InstanceServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/InstanceServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/InstanceServiceTest.java
index cb4e5f8..e975a5b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/InstanceServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/InstanceServiceTest.java
@@ -22,6 +22,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -78,7 +79,7 @@ public class InstanceServiceTest extends BaseServiceTest {
     private String m_instanceId;
 
     private TestInstanceService(String feedName, String instanceId) {
-      super(feedName);
+      super(ApiVersion.v1, feedName);
       m_feedName = feedName;
       m_instanceId = instanceId;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/JobServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/JobServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/JobServiceTest.java
index 6e0fa96..97f264a 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/JobServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/JobServiceTest.java
@@ -28,6 +28,7 @@ import javax.ws.rs.core.UriInfo;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 /**
  * Unit tests for JobService.
@@ -62,7 +63,7 @@ public class JobServiceTest extends BaseServiceTest {
     private String clusterName;
 
     public TestJobService(String clusterName, String workflowId) {
-      super(clusterName, workflowId);
+      super(ApiVersion.v1, clusterName, workflowId);
       this.clusterName = clusterName;
       this.workflowId = workflowId;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/LdapSyncEventServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/LdapSyncEventServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/LdapSyncEventServiceTest.java
index af458b2..960bb66 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/LdapSyncEventServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/LdapSyncEventServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.core.HttpHeaders;
@@ -69,7 +70,7 @@ public class LdapSyncEventServiceTest extends BaseServiceTest {
   private class TestLdapSyncEventService extends LdapSyncEventService {
 
     private TestLdapSyncEventService() {
-      super();
+      super(ApiVersion.v1);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/MemberServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/MemberServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/MemberServiceTest.java
index b3bf3fb..1e8e125 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/MemberServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/MemberServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource.Type;
 
 import javax.ws.rs.core.HttpHeaders;
@@ -84,7 +85,7 @@ public class MemberServiceTest extends BaseServiceTest {
 
   private class TestMemberService extends MemberService {
     public TestMemberService(String groupName) {
-      super(groupName);
+      super(ApiVersion.v1, groupName);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/PermissionServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/PermissionServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/PermissionServiceTest.java
index 620643f..00b74f5 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/PermissionServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/PermissionServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -78,6 +79,7 @@ public class PermissionServiceTest extends BaseServiceTest {
     private String id;
 
     private TestPermissionService(String id) {
+      super(ApiVersion.v1);
       this.id = id;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/PreUpgradeCheckServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/PreUpgradeCheckServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/PreUpgradeCheckServiceTest.java
index f851133..a7beb28 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/PreUpgradeCheckServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/PreUpgradeCheckServiceTest.java
@@ -29,6 +29,7 @@ import javax.ws.rs.core.UriInfo;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource.Type;
 
 /**
@@ -56,7 +57,7 @@ public class PreUpgradeCheckServiceTest extends BaseServiceTest {
   private class TestPreUpgradeCheckService extends PreUpgradeCheckService {
 
     public TestPreUpgradeCheckService(String clusterName) {
-      super(clusterName);
+      super(ApiVersion.v1, clusterName);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/PrivilegeServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/PrivilegeServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/PrivilegeServiceTest.java
index d9f3e28..17268c7 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/PrivilegeServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/PrivilegeServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -91,6 +92,7 @@ public class PrivilegeServiceTest extends BaseServiceTest {
     private String id;
 
     private TestPrivilegeService(String id) {
+      super(ApiVersion.v1);
       this.id = id;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/RecommendationServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/RecommendationServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/RecommendationServiceTest.java
index a1a0908..68eb8dd 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/RecommendationServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/RecommendationServiceTest.java
@@ -30,6 +30,7 @@ import javax.ws.rs.core.UriInfo;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 /**
  * Unit tests for RecommendationService.
@@ -41,7 +42,7 @@ public class RecommendationServiceTest extends BaseServiceTest {
     List<ServiceTestInvocation> listInvocations = new ArrayList<ServiceTestInvocation>();
 
     //getRecommendation
-    RecommendationService service = new TestRecommendationService("stackName", "stackVersion");
+    StacksService service = new TestRecommendationService("stackName", "stackVersion");
     Method m = service.getClass().getMethod("getRecommendation", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class);
     Object[] args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "stackName", "stackVersion"};
     listInvocations.add(new ServiceTestInvocation(Request.Type.POST, service, m, args, "body"));
@@ -49,12 +50,12 @@ public class RecommendationServiceTest extends BaseServiceTest {
     return listInvocations;
   }
 
-  private class TestRecommendationService extends RecommendationService {
+  private class TestRecommendationService extends StacksService {
     private String stackName;
     private String stackVersion;
 
     private TestRecommendationService(String stackName, String stackVersion) {
-      super();
+      super(ApiVersion.v1);
       this.stackName = stackName;
       this.stackVersion = stackVersion;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/RepositoryServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/RepositoryServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/RepositoryServiceTest.java
index 013fed1..444d06e 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/RepositoryServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/RepositoryServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource.Type;
 
 import javax.ws.rs.core.HttpHeaders;
@@ -81,7 +82,7 @@ public class RepositoryServiceTest extends BaseServiceTest {
   private class TestRepositoryService extends RepositoryService {
 
     public TestRepositoryService() {
-      super(new HashMap<Type, String>());
+      super(ApiVersion.v1, new HashMap<Type, String>());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/RoleAuthorizationServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/RoleAuthorizationServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/RoleAuthorizationServiceTest.java
index ed7b7c9..8b6ae39 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/RoleAuthorizationServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/RoleAuthorizationServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -59,6 +60,7 @@ public class RoleAuthorizationServiceTest extends BaseServiceTest {
     private String id;
 
     private TestRoleAuthorizationService(String id) {
+      super(ApiVersion.v1);
       this.id = id;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/RootServiceServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/RootServiceServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/RootServiceServiceTest.java
index 310d69f..93ddb2e 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/RootServiceServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/RootServiceServiceTest.java
@@ -30,6 +30,7 @@ import javax.ws.rs.core.UriInfo;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 /**
 * Unit tests for RootServiceService.
@@ -93,6 +94,7 @@ public class RootServiceServiceTest extends BaseServiceTest {
     private String m_hostName;
 
     private TestRootServiceService(String serviceName, String componentName, String hostName) {
+      super(ApiVersion.v1);
       m_serviceName = serviceName;
       m_componentName = componentName;
       m_hostName = hostName;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ServiceServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ServiceServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ServiceServiceTest.java
index 5c3e3a7..119eb20 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ServiceServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ServiceServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -133,13 +134,13 @@ public class ServiceServiceTest extends BaseServiceTest {
     private String m_artifact_id;
 
     private TestServiceService(String clusterId, String serviceId) {
-      super(clusterId);
+      super(ApiVersion.v1, clusterId);
       m_clusterId = clusterId;
       m_serviceId = serviceId;
     }
 
     private TestServiceService(String clusterId, String serviceId, String artifactId) {
-      super(clusterId);
+      super(ApiVersion.v1, clusterId);
       m_clusterId = clusterId;
       m_serviceId = serviceId;
       m_artifact_id = artifactId;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/SettingServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/SettingServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/SettingServiceTest.java
index 598e420..e660fa7 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/SettingServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/SettingServiceTest.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -74,6 +75,7 @@ public class SettingServiceTest extends BaseServiceTest {
     private String settingName;
 
     private TestSettingService(String settingName) {
+      super(ApiVersion.v1);
       this.settingName = settingName;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/StacksServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/StacksServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/StacksServiceTest.java
index dd43ee3..8e66173 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/StacksServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/StacksServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.easymock.EasyMock;
 import org.junit.Test;
 
@@ -152,6 +153,7 @@ public class StacksServiceTest extends BaseServiceTest {
     private String m_stackVersion;
 
     private TestStacksService(String stackName, String stackVersion) {
+      super(ApiVersion.v1);
       m_stackId = stackName;
       m_stackVersion = stackVersion;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/TargetClusterServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/TargetClusterServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/TargetClusterServiceTest.java
index 3394e8e..f2aa75b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/TargetClusterServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/TargetClusterServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -79,6 +80,7 @@ public class TargetClusterServiceTest extends BaseServiceTest {
     private String m_targetClusterId;
 
     private TestTargetClusterService(String targetClusterId) {
+      super(ApiVersion.v1);
       m_targetClusterId = targetClusterId;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/TaskAttemptServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/TaskAttemptServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/TaskAttemptServiceTest.java
index 91a893a..b228173 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/TaskAttemptServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/TaskAttemptServiceTest.java
@@ -28,6 +28,7 @@ import javax.ws.rs.core.UriInfo;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 /**
  * Unit tests for TaskAttemptService.
@@ -65,7 +66,7 @@ public class TaskAttemptServiceTest extends BaseServiceTest {
 
     public TestTaskAttemptService(String clusterName, String workflowId,
         String jobId) {
-      super(clusterName, workflowId, jobId);
+      super(ApiVersion.v1, clusterName, workflowId, jobId);
       this.clusterName = clusterName;
       this.workflowId = workflowId;
       this.jobId = jobId;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/UpgradeItemServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/UpgradeItemServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/UpgradeItemServiceTest.java
index 68fe87f..e006fbb 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/UpgradeItemServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/UpgradeItemServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.junit.Assert;
 
 import javax.ws.rs.core.HttpHeaders;
@@ -49,7 +50,7 @@ public class UpgradeItemServiceTest extends BaseServiceTest {
     private Long m_upgradeItemId;
 
     private TestUpgradeItemService(String clusterName, String upgradeId, String upgradeGroupId, Long upgradeItemId) {
-      super(clusterName, upgradeId, upgradeGroupId);
+      super(ApiVersion.v1, clusterName, upgradeId, upgradeGroupId);
 
       m_upgradeItemId = upgradeItemId;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserAuthorizationServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserAuthorizationServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserAuthorizationServiceTest.java
index c3270bb..93f7731 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserAuthorizationServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserAuthorizationServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.junit.Test;
 
@@ -59,7 +60,7 @@ public class UserAuthorizationServiceTest extends BaseServiceTest {
   @Test
   public void testCreateAuthorizationResourceWithUppercaseUsername() {
     // GIVEN
-    UserAuthorizationService userAuthorizationService= new UserAuthorizationService("Jdoe");
+    UserAuthorizationService userAuthorizationService= new UserAuthorizationService(ApiVersion.v1, "Jdoe");
     // WHEN
     ResourceInstance result = userAuthorizationService.createAuthorizationResource("id");
     // THEN
@@ -71,7 +72,7 @@ public class UserAuthorizationServiceTest extends BaseServiceTest {
     private String id;
 
     private TestUserAuthorizationService(String id) {
-      super("jdoe");
+      super(ApiVersion.v1, "jdoe");
       this.id = id;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserPrivilegeServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserPrivilegeServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserPrivilegeServiceTest.java
index db2d38a..0dfa7df 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserPrivilegeServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserPrivilegeServiceTest.java
@@ -33,6 +33,7 @@ import junit.framework.Assert;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.Resource.Type;
 import org.easymock.EasyMock;
@@ -88,7 +89,7 @@ public class UserPrivilegeServiceTest extends BaseServiceTest {
   @Test
   public void testCreatePrivilegeResourcesWithUppercaseUsername() {
     // GIVEN
-    UserPrivilegeService userPrivilegeService = new UserPrivilegeService("User");
+    UserPrivilegeService userPrivilegeService = new UserPrivilegeService(ApiVersion.v1, "User");
     // WHEN
     ResourceInstance result = userPrivilegeService.createPrivilegeResource("test");
     // THEN
@@ -98,7 +99,7 @@ public class UserPrivilegeServiceTest extends BaseServiceTest {
   private class TestUserPrivilegeService extends UserPrivilegeService {
 
     public TestUserPrivilegeService() {
-      super("user");
+      super(ApiVersion.v1, "user");
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserServiceTest.java
index 0ed0a66..495e244 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/UserServiceTest.java
@@ -23,6 +23,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.junit.Test;
@@ -45,6 +46,10 @@ public class UserServiceTest {
   }
 
   class TestUserService extends UserService {
+    public TestUserService() {
+      super(ApiVersion.v1);
+    }
+
     @Override
     protected Response handleRequest(HttpHeaders headers, String body, UriInfo uriInfo,
                                      Request.Type requestType, final ResourceInstance resource) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ValidationServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ValidationServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ValidationServiceTest.java
index aec68e6..04295df 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ValidationServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ValidationServiceTest.java
@@ -30,6 +30,7 @@ import javax.ws.rs.core.UriInfo;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 /**
  * Unit tests for ValidationService.
@@ -41,7 +42,7 @@ public class ValidationServiceTest extends BaseServiceTest {
     List<ServiceTestInvocation> listInvocations = new ArrayList<ServiceTestInvocation>();
 
     //getValidation
-    ValidationService service = new TestValidationService("stackName", "stackVersion");
+    StacksService service = new TestValidationService("stackName", "stackVersion");
     Method m = service.getClass().getMethod("getValidation", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class);
     Object[] args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "stackName", "stackVersion"};
     listInvocations.add(new ServiceTestInvocation(Request.Type.POST, service, m, args, "body"));
@@ -49,12 +50,12 @@ public class ValidationServiceTest extends BaseServiceTest {
     return listInvocations;
   }
 
-  private class TestValidationService extends ValidationService {
+  private class TestValidationService extends StacksService {
     private String stackName;
     private String stackVersion;
 
     private TestValidationService(String stackName, String stackVersion) {
-      super();
+      super(ApiVersion.v1);
       this.stackName = stackName;
       this.stackVersion = stackVersion;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewDataMigrationServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewDataMigrationServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewDataMigrationServiceTest.java
index 1eb7ac2..8e3eb9c 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewDataMigrationServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewDataMigrationServiceTest.java
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.api.services;
 
 import junit.framework.Assert;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.orm.entities.ViewEntity;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
 import org.apache.ambari.server.view.ViewDataMigrationContextImpl;
@@ -152,7 +153,7 @@ public class ViewDataMigrationServiceTest {
     private ViewDataMigrationContextImpl migrationContext;
 
     public TestViewDataMigrationService(String viewName, String viewVersion, String instanceName) {
-      super(viewName, viewVersion, instanceName);
+      super(ApiVersion.v1, viewName, viewVersion, instanceName);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewExternalSubResourceServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewExternalSubResourceServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewExternalSubResourceServiceTest.java
index 155f91e..4ecaaa3 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewExternalSubResourceServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewExternalSubResourceServiceTest.java
@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.api.services;
 
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntityTest;
@@ -32,7 +33,7 @@ public class ViewExternalSubResourceServiceTest {
     Resource.Type type = new Resource.Type("resource");
 
     ViewInstanceEntity definition = ViewInstanceEntityTest.getViewInstanceEntity();
-    ViewExternalSubResourceService service = new ViewExternalSubResourceService(type, definition);
+    ViewExternalSubResourceService service = new ViewExternalSubResourceService(ApiVersion.v1, type, definition);
 
     Object fooService = new Object();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewPermissionServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewPermissionServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewPermissionServiceTest.java
index f841be9..701ee13 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewPermissionServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewPermissionServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -72,7 +73,7 @@ public class ViewPermissionServiceTest extends BaseServiceTest {
 
     private TestViewPermissionService(String viewName, String version, String permissionId) {
 
-      super(viewName, version);
+      super(ApiVersion.v1, viewName, version);
       this.permissionId = permissionId;
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewSubResourceServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewSubResourceServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewSubResourceServiceTest.java
index 158ccf8..eb96ec4 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewSubResourceServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewSubResourceServiceTest.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.api.util.TreeNode;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
@@ -131,7 +132,7 @@ public class ViewSubResourceServiceTest extends BaseServiceTest {
     Resource.Type type = new Resource.Type("subResource");
 
     // get resource
-    ViewSubResourceService service = new ViewSubResourceService(type, viewInstanceEntity);
+    ViewSubResourceService service = new ViewSubResourceService(ApiVersion.v1, type, viewInstanceEntity);
 
     ResultSerializer serializer = service.getResultSerializer(MediaType.TEXT_PLAIN_TYPE);
 
@@ -189,7 +190,7 @@ public class ViewSubResourceServiceTest extends BaseServiceTest {
     Resource.Type type = new Resource.Type("subResource");
 
     // get resource
-    ViewSubResourceService service = new ViewSubResourceService(type, viewInstanceEntity);
+    ViewSubResourceService service = new ViewSubResourceService(ApiVersion.v1, type, viewInstanceEntity);
 
     ResultSerializer serializer = service.getResultSerializer(MediaType.APPLICATION_JSON_TYPE);
 
@@ -218,7 +219,7 @@ public class ViewSubResourceServiceTest extends BaseServiceTest {
      * Construct a view sub-resource service.
      */
     public TestViewSubResourceService(Resource.Type type, ViewInstanceEntity viewInstanceDefinition) {
-      super(type, viewInstanceDefinition);
+      super(ApiVersion.v1, type, viewInstanceDefinition);
     }
 
     public Response getSubResource1(@Context HttpHeaders headers, @Context UriInfo ui,

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/WorkflowServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/WorkflowServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/WorkflowServiceTest.java
index 9969e59..305ab8b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/WorkflowServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/WorkflowServiceTest.java
@@ -28,6 +28,7 @@ import javax.ws.rs.core.UriInfo;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.api.util.ApiVersion;
 
 /**
  * Unit tests for WorkflowService.
@@ -61,7 +62,7 @@ public class WorkflowServiceTest extends BaseServiceTest {
     private String clusterName;
 
     public TestWorkflowService(String clusterName) {
-      super(clusterName);
+      super(ApiVersion.v1, clusterName);
       this.clusterName = clusterName;
     }
 


[08/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/query-tabs.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/query-tabs.scss b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/query-tabs.scss
new file mode 100644
index 0000000..9f803b4
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/query-tabs.scss
@@ -0,0 +1,69 @@
+/**
+* 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.
+*/
+
+.query-menu {
+  margin-top: 58px;
+
+  span, popover {
+    cursor: pointer;
+    display: block;
+    border-bottom: 1px solid $border-color;
+    padding: 10px;
+  }
+}
+
+.fa.panel-action-icon {
+  line-height: 22px;
+  font-size: 16px;
+}
+
+.editor-overlay {
+  width: 100%;
+  overflow-y: scroll;
+  height: calc(100% - 57px);
+  top: 57px;
+  left: 0;
+  background-color: #fff;
+  position: absolute;
+  padding: 10px 15px;
+  z-index: 1000;
+
+  border: 1px solid $border-color;
+  -webkit-animation-duration: .5s;
+          animation-duration: .5s;
+  -webkit-animation-fill-mode: both;
+          animation-fill-mode: both;
+}
+
+.message-body {
+  margin-top: 10px;
+}
+
+.query-menu-tab {
+  position: relative;
+}
+.query-menu-tab .badge {
+  position: absolute;
+  top: -4px;
+  right: 0px;
+  background-color: red;
+  color: #fff;
+  padding: 2px 4px;
+  font-weight: bold;
+  z-index: 9999;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/vars.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/vars.scss b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/vars.scss
new file mode 100644
index 0000000..184ac9d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/styles/vars.scss
@@ -0,0 +1,21 @@
+/**
+* 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.
+*/
+
+$panel-background: #f5f5f5;
+$placeholder-color: #aaa;
+$border-color: #ddd;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/application.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/application.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/application.hbs
new file mode 100644
index 0000000..db053fa
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/application.hbs
@@ -0,0 +1,26 @@
+{{!
+* 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.
+}}
+
+{{notify-widget notifications=notifications}}
+{{navbar-widget}}
+
+<div id="content">
+  {{outlet}}
+
+  {{outlet "modal"}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/alert-message-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/alert-message-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/alert-message-widget.hbs
new file mode 100644
index 0000000..0901b30
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/alert-message-widget.hbs
@@ -0,0 +1,28 @@
+{{!
+* 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.
+}}
+
+<div {{bind-attr class=":alert :alert-dismissible message.typeClass"}}>
+  <button type="button" class="close" data-dismiss="alert" aria-hidden="true" {{action "remove"}}>&times;</button>
+  <strong {{action 'toggleMessage'}}>{{tb-helper message.title}}</strong>
+
+  {{#if message.isExpanded}}
+    <div class="alert-message">
+      {{message.content}}
+    </div>
+  {{/if}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/collapsible-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/collapsible-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/collapsible-widget.hbs
new file mode 100644
index 0000000..68ff307
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/collapsible-widget.hbs
@@ -0,0 +1,33 @@
+{{!
+* 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.
+}}
+
+<div class="clearfix">
+
+  <a {{action "toggle"}} {{bind-attr class=":fa iconClass :collapsible-row" data-original-title=heading}}
+          data-toggle="tooltip" data-placement="top"
+          title>{{heading}}</a>
+
+  <div class="pull-right widget-controls">
+    {{#each control in controls}}
+      <a {{action 'sendControlAction' control.action}} {{bind-attr class=":fa control.icon" title="control.tooltip"}}></a>
+    {{/each}}
+  </div>
+</div>
+{{#if isExpanded}}
+  {{yield}}
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/column-filter-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/column-filter-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/column-filter-widget.hbs
new file mode 100644
index 0000000..3435093
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/column-filter-widget.hbs
@@ -0,0 +1,42 @@
+{{!
+* 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.
+}}
+
+{{#if column.dateRange}}
+    {{date-range-widget class="pull-left history-date-range"
+                        rangeChanged="sendFilter"
+                        dateRange=column.dateRange}}
+{{else}}
+  {{#if column.numberRange}}
+    {{number-range-widget class="pull-left"
+                          numberRange=column.numberRange
+                          rangeChanged="sendFilter"}}
+  {{else}}
+    {{extended-input type="text"
+                     class="pull-left form-control input-sm"
+                     placeholderTranslation=column.caption
+                     value=filterValue
+                     valueChanged="sendFilter"}}
+  {{/if}}
+{{/if}}
+<span {{action "sendSort"}}>
+  {{#if isSorted}}
+    <a {{bind-attr class=":pull-right :fa sortAscending:fa-sort-asc:fa-sort-desc"}}></a>
+  {{else}}
+    <i class="pull-right fa fa-unsorted"></i>
+  {{/if}}
+</span>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/date-range-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/date-range-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/date-range-widget.hbs
new file mode 100644
index 0000000..4b9686e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/date-range-widget.hbs
@@ -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
+*
+*     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.
+}}
+
+<div class="form-inline">
+    {{input type="text" value=displayFromDate class="input-sm form-control fromDate"}}
+    {{input type="text" value=displayToDate class="input-sm form-control toDate"}}
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/expander-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/expander-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/expander-widget.hbs
new file mode 100644
index 0000000..386556c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/expander-widget.hbs
@@ -0,0 +1,31 @@
+{{!
+* 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.
+}}
+
+<div class="panel panel-default no-margin">
+  <div class="panel-heading accordion-heading" {{action "toggle"}}>
+      <span {{bind-attr class=":fa isExpanded:fa-caret-down:fa-caret-right"}}></span>
+      <a class="accordion-toggle">{{heading}}</a>
+      <span class="badge pull-right">{{count}}</span>
+  </div>
+
+  <div class="panel-body accordion-body collapse">
+    <div class="accordion-inner">
+      {{yield}}
+    </div>
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/input-header.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/input-header.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/input-header.hbs
new file mode 100644
index 0000000..b2349fa
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/input-header.hbs
@@ -0,0 +1,20 @@
+{{!
+* 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.
+}}
+
+<td  {{bind-attr class="noPrecision:hidden:visible"}}>{{input type="number" placeholder="precision" class="form-control" value=column.precision }}</td>
+<td {{bind-attr class="noScale:hidden:visible"}}>{{input placeholder="scale" type="number" class="form-control" value=column.scale }}</td>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/job-tr-view.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/job-tr-view.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/job-tr-view.hbs
new file mode 100644
index 0000000..6b01946
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/job-tr-view.hbs
@@ -0,0 +1,49 @@
+{{!
+* 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.
+}}
+
+<tr class="main-row" {{action "requestFile"}}>
+  <td>
+  {{#link-to "index.historyQuery" job}}
+    {{job.title}}
+  {{/link-to}}
+  </td>
+  <td {{bind-attr class=job.uppercaseStatus}}>{{all-uppercase job.status}}</td>
+  <td>{{date-binding job "dateSubmittedTimestamp"}}</td>
+  <td>{{job.duration}}</td>
+  <td>
+    <a class="fa fa-expand pull-right"></a>
+  </td>
+</tr>
+{{#if expanded}}
+  <tr class="secondary-row">
+    <td colspan="5">
+      {{code-helper job.file.fileContent}}
+
+      {{#if canStop}}
+        <button type="button" {{bind-attr class=":btn :btn-warning :btn-sm :pull-right job.isCancelling:disabled"}} {{action "stopJob"}}>
+          {{#if job.isCancelling}}
+            {{t "buttons.stoppingJob"}}
+            <div class="spinner small inline-spinner"></div>
+          {{else}}
+            {{t "buttons.stopJob"}}
+          {{/if}}
+        </button>
+      {{/if}}
+    </td>
+  </tr>
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/modal-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/modal-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/modal-widget.hbs
new file mode 100644
index 0000000..8f2dec7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/modal-widget.hbs
@@ -0,0 +1,35 @@
+{{!
+* 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.
+}}
+
+<div class="modal fade">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close"><span aria-hidden="true" data-dismiss="modal">&times;</span><span class="sr-only">Close</span></button>
+        <h4 class="modal-title">{{tb-helper heading}}</h4>
+      </div>
+      <div class="modal-body">
+        {{yield}}
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-sm btn-danger" data-dismiss="modal">{{t "buttons.close"}}</button>
+        <button type="button" class="btn btn-sm btn-success" {{action 'ok'}}>{{t "buttons.ok"}}</button>
+      </div>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/navbar-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/navbar-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/navbar-widget.hbs
new file mode 100644
index 0000000..f13f7b5
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/navbar-widget.hbs
@@ -0,0 +1,45 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*     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.
+}}
+
+<nav class="navbar navbar-default no-margin" role="navigation">
+  <div class="container-fluid">
+    <!-- Brand and toggle get grouped for better mobile display -->
+    <div class="navbar-header">
+      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+        <span class="sr-only">Toggle navigation</span>
+        <span class="icon-bar"></span>
+        <span class="icon-bar"></span>
+        <span class="icon-bar"></span>
+      </button>
+      {{#link-to "index" classNames="navbar-brand mozBoxSizeFix"}}
+        {{view.title}}
+      {{/link-to}}
+    </div>
+
+    <!-- Collect the nav links, forms, and other content for toggling -->
+    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+       <ul class="nav navbar-nav">
+        {{#each item in view.items}}
+          {{#link-to item.path tagName="li"}}
+            <a>{{tb-helper "text" item}}</a>
+          {{/link-to}}
+        {{/each}}
+      </ul>
+    </div>
+  </div>
+</nav>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/no-bubbling.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/no-bubbling.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/no-bubbling.hbs
new file mode 100644
index 0000000..6ae472f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/no-bubbling.hbs
@@ -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.
+}}
+
+{{yield}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/notify-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/notify-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/notify-widget.hbs
new file mode 100644
index 0000000..5f905a8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/notify-widget.hbs
@@ -0,0 +1,21 @@
+{{!
+* 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.
+}}
+
+{{#each notification in notifications}}
+  {{view "notification" notification=notification}}
+{{/each}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/number-range-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/number-range-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/number-range-widget.hbs
new file mode 100644
index 0000000..da99e9c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/number-range-widget.hbs
@@ -0,0 +1,23 @@
+{{!
+* 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.
+}}
+
+<div class="slider"></div>
+<div class="slider-labels">
+  <span class="pull-left">{{numberRange.fromDuration}}</span>
+  <span class="pull-right">{{numberRange.toDuration}}</span>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/panel-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/panel-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/panel-widget.hbs
new file mode 100644
index 0000000..a8af586
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/panel-widget.hbs
@@ -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.
+}}
+
+<div {{bind-attr class=":panel :panel-default classNames"}}>
+  {{#if heading}}
+    <div class="panel-heading">
+      {{#if menuItems}}
+          <div class="dropdown pull-right">
+              <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{menuHeading}} <b class="caret"></b></a>
+
+              <ul class="dropdown-menu" role="menu">
+                  {{#each item in menuItems}}
+                      {{#if item.href}}
+                          <li><a {{bind-attr href=item.href}}>{{item.title}}</a></li>
+                      {{else}}
+                          <li><a {{action "sendMenuItemAction" item.action}}>{{item.title}}</a></li>
+                      {{/if}}
+                  {{/each}}
+              </ul>
+          </div>
+      {{/if}}
+
+      {{#if iconActions}}
+        {{#each iconAction in iconActions}}
+        <i {{action "sendMenuItemAction" iconAction.action}}
+          {{bind-attr class=":pull-right :panel-action-icon :fa iconAction.icon" title="iconAction.tooltip"}}></i>
+        {{/each}}
+      {{/if}}
+
+      <strong>{{heading}}</strong>
+      {{#if isLoading}}
+        <div class="spinner small pull-right"></div>
+      {{/if}}
+    </div>
+  {{/if}}
+  <div class="panel-body">
+    {{yield}}
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/popover-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/popover-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/popover-widget.hbs
new file mode 100644
index 0000000..f7c6d9c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/popover-widget.hbs
@@ -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.
+}}
+
+<span class="hide"> {{yield}} </span>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/progress-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/progress-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/progress-widget.hbs
new file mode 100644
index 0000000..2ea7b94
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/progress-widget.hbs
@@ -0,0 +1,23 @@
+{{!
+* 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.
+}}
+
+<div class="progress">
+  <div {{bind-attr class=":progress-bar :progress-bar-success" style=style}}>
+    {{percentage}}
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/query-editor.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/query-editor.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/query-editor.hbs
new file mode 100644
index 0000000..4ec9259
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/query-editor.hbs
@@ -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.
+}}
+
+{{textarea id="code-mirror" rows="15" cols="20" value=query}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/select-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/select-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/select-widget.hbs
new file mode 100644
index 0000000..6da1f3e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/select-widget.hbs
@@ -0,0 +1,39 @@
+{{!
+* 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.
+}}
+
+<div class="btn-group">
+  <a class="btn btn-default dropdown-toggle" data-toggle="dropdown">
+      <span class="selected-item pull-left">{{selectedLabel}}</span>
+      <span class="pull-right fa fa-caret-down"></span>
+  </a>
+  <ul class="dropdown-menu">
+    {{#each item in items}}
+      <li {{action "select" item}}>
+        <a>{{path-binding item labelPath}}
+          {{#if canEdit}}
+            <span class="fa fa-remove pull-right" {{action "remove" item}}></span>
+            <span class="fa fa-edit pull-right" {{action "edit" item}}></span>
+          {{/if}}
+        </a>
+      </li>
+    {{/each}}
+    {{#if canAdd}}
+      <li {{action "add"}}><a>{{t "buttons.addItem"}}</a></li>
+    {{/if}}
+  </ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/tabs-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/tabs-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/tabs-widget.hbs
new file mode 100644
index 0000000..edef7fd
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/tabs-widget.hbs
@@ -0,0 +1,41 @@
+{{!
+* 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.
+}}
+
+<ul class="nav nav-tabs">
+  {{#each tab in tabs}}
+    {{#if tab.visible}}
+      {{#if tab.path}}
+        {{#link-to tab.path tab.id tagName="li"}}
+          <a {{action 'titleClick' tab on="doubleClick"}}>
+            {{tab.name}}
+            {{#if tab.isDirty}}*{{/if}}
+            {{#if view.removeEnabled}}
+              <i class="fa fa-remove" {{action 'remove' tab}}></i>
+            {{/if}}
+          </a>
+        {{/link-to}}
+      {{else}}
+        <li {{bind-attr class="tab.active:active"}} {{action 'selectTab' tab}}>
+          <a>{{tab.name}}</a>
+        </li>
+      {{/if}}
+    {{/if}}
+  {{/each}}
+</ul>
+
+{{yield}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/tree-view.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/tree-view.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/tree-view.hbs
new file mode 100644
index 0000000..cb83ec3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/tree-view.hbs
@@ -0,0 +1,28 @@
+{{!
+* 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.
+}}
+
+<ul class="list-unstyled">
+  {{#each item in content}}
+    <li>
+      {{item.text}}
+      {{#if item.contents}}
+        {{tree-view content=item.contents}}
+      {{/if}}
+    </li>
+  {{/each}}
+</ul>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/udf-tr-view.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/udf-tr-view.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/udf-tr-view.hbs
new file mode 100644
index 0000000..4b5cd61
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/udf-tr-view.hbs
@@ -0,0 +1,77 @@
+{{!
+* 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.
+}}
+
+<td>
+  {{#if udf.isEditing}}
+    {{#if udf.isEditingResource}}
+      {{extended-input type="text"
+                       class="pull-left form-control halfed input-sm"
+                       placeholderTranslation="placeholders.fileResource.name"
+                       value=udf.fileResource.name}}
+      {{extended-input type="text"
+                       class="pull-left form-control halfed input-sm"
+                       placeholderTranslation="placeholders.fileResource.path"
+                       value=udf.fileResource.path}}
+    {{else}}
+      {{select-widget items=fileResources
+                      selectedValue=udf.fileResource
+                      labelPath="name"
+                      defaultLabelTranslation="placeholders.select.file"
+                      itemAdded="addFileResource"
+                      itemEdited="editFileResource"
+                      itemRemoved="deleteFileResource"
+                      canAdd=true
+                      canEdit=true}}
+    {{/if}}
+  {{else}}
+    {{#if udf.fileResource}}
+      {{udf.fileResource.name}}  ({{udf.fileResource.path}})
+    {{/if}}
+  {{/if}}
+</td>
+{{#each column in columns}}
+  <td>
+    {{#if udf.isEditing}}
+      {{extended-input type="text"
+                       class="pull-left form-control input-sm"
+                       placeholderTranslation=column.caption
+                       dynamicContextBinding="udf"
+                       dynamicValueBinding="column.property"}}
+    {{else}}
+      {{path-binding udf column.property}}
+    {{/if}}
+  </td>
+{{/each}}
+<td>
+  {{#if udf.isEditing}}
+    <div class="pull-right">
+      <button type="button" class="btn btn-sm btn-warning" {{action "cancel"}}>{{t "buttons.cancel"}}</button>
+      <button type="button" class="btn btn-sm btn-success" {{action "save"}}>{{t "buttons.save"}}</button>
+    </div>
+  {{else}}
+    <div class="btn-group pull-right">
+      <span data-toggle="dropdown">
+        <a class="fa fa-gear"></a>
+      </span>
+      <ul class="dropdown-menu" role="menu">
+        <li {{action 'editUdf'}}><a>{{t 'buttons.edit'}}</a></li>
+        <li {{action 'deleteUdf'}}><a>{{t 'buttons.delete'}}</a></li>
+      </ul>
+    </div>
+  {{/if}}
+</td>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/visualization-tabs-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/visualization-tabs-widget.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/visualization-tabs-widget.hbs
new file mode 100644
index 0000000..dad5e41
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/components/visualization-tabs-widget.hbs
@@ -0,0 +1,27 @@
+{{!
+* 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.
+}}
+
+<ul class="nav nav-tabs visualization-tabs">
+  {{#each tab in tabs}}
+      <li {{bind-attr class="tab.active:active"}} {{action 'selectTab' tab}}>
+        <a>{{tab.name}}</a>
+      </li>
+  {{/each}}
+</ul>
+
+<iframe {{bind-attr src=selectedTab.url}} id="visualization_frame" style="width:100%;height:1000px;border:0px;" allowfullscreen="true"></iframe>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/databases-search-results.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/databases-search-results.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/databases-search-results.hbs
new file mode 100644
index 0000000..007d9ca
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/databases-search-results.hbs
@@ -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.
+}}
+
+{{#if tableSearchResults.tables}}
+  <div class="databases">
+    <a class="fa fa-database"> {{selectedDatabase.name}}</a>
+
+    <div class="tables">
+      {{#each table in tableSearchResults.tables}}
+        <a class="fa fa-th"> {{table.name}}</a>
+
+        <div class="columns">
+          {{#each column in table.columns}}
+            <div>
+              <strong>{{column.name}}</strong>
+              <span class="pull-right">{{column.type}}</span>
+            </div>
+          {{/each}}
+
+          {{#if table.hasNext}}
+            <strong><a {{action "showMoreResultColumns" table}}>{{t "buttons.loadMore"}}</a></strong>
+          {{/if}}
+        </div>
+      {{/each}}
+
+      {{#if tableSearchResults.hasNext}}
+        <strong><a {{action "showMoreResultTables" database}}>{{t "buttons.loadMore"}}</a></strong>
+      {{/if}}
+    </div>
+  </div>
+{{else}}
+  <div class="alert alert-warning database-explorer-alert" role="alert">
+    {{t "labels.noTablesMatch"}} <strong>&quot;{{tablesSearchTerm}}&quot;</strong>
+  </div>
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/databases-tree.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/databases-tree.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/databases-tree.hbs
new file mode 100644
index 0000000..5023c40
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/databases-tree.hbs
@@ -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.
+}}
+
+<div class="databases">
+  {{#each database in databases}}
+    {{#collapsible-widget heading=database.name isExpanded=database.isExpanded iconClass="fa-database" expanded="getTables" toggledParam=database}}
+      {{#if database.isExpanded}}
+        <div class="tables">
+          {{#each table in database.visibleTables}}
+            {{#collapsible-widget heading=table.name isExpanded=table.isExpanded toggledParam=database iconClass="fa-table" expanded="getColumns" controls=tableControls}}
+              {{#if table.isExpanded}}
+                <div class="columns">
+                  {{#each column in table.visibleColumns}}
+                    <div>
+                      <div class="column-name" {{bind-attr data-original-title=column.name}}
+                              data-toggle="tooltip" data-placement="top" title>{{column.name}}
+                      </div>
+                      <span class="pull-right widget-controls">{{format-column-type column}}</span>
+                    </div>
+                  {{/each}}
+                  {{#if table.canGetNextPage}}
+                    <strong><a {{action "showMoreColumns" table database}}>{{t "buttons.loadMore"}}</a></strong>
+                  {{/if}}
+                </div>
+              {{/if}}
+            {{/collapsible-widget}}
+          {{/each}}
+          {{#if database.canGetNextPage}}
+            <strong><a {{action "showMoreTables" database}}>{{t "buttons.loadMore"}}</a></strong>
+          {{/if}}
+        </div>
+      {{/if}}
+    {{/collapsible-widget}}
+  {{/each}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/databases.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/databases.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/databases.hbs
new file mode 100644
index 0000000..290cdac
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/databases.hbs
@@ -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.
+}}
+
+{{#panel-widget headingTranslation="titles.database" isLoading=isLoading classNames="database-explorer" iconActions=panelIconActions}}
+  {{#if databases}}
+
+    {{typeahead-widget
+        content=databases
+        optionValuePath="id"
+        optionLabelPath="name"
+        selection=selectedDatabase
+    }}
+
+    <hr />
+
+    {{#if selectedDatabase}}
+      {{extended-input class="form-control input-sm mozBoxSizeFix"
+                       placeholderTranslation="placeholders.search.tables"
+                       valueSearched="searchTables"
+                       value=tableSearchTerm}}
+
+      <hr />
+    {{/if}}
+
+
+    {{#if tableSearchResults.tables}}
+      {{extended-input class="form-control input-sm mozBoxSizeFix"
+                       placeholderTranslation="placeholders.search.columns"
+                       valueSearched="searchColumns"
+                       value=columnSearchTerm}}
+
+      <hr />
+    {{/if}}
+
+    {{#tabs-widget tabs=tabs selectedTab=selectedTab}}
+      {{partial selectedTab.view}}
+    {{/tabs-widget}}
+  {{/if}}
+{{/panel-widget}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/history.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/history.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/history.hbs
new file mode 100644
index 0000000..052498e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/history.hbs
@@ -0,0 +1,63 @@
+{{!
+* 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.
+}}
+
+<table class="table table-expandable">
+  <thead>
+    <tr>
+      {{#each column in columns}}
+        <th>
+          {{#if column.caption}}
+            {{column-filter-widget class="pull-left"
+                                   column=column
+                                   filterValue=column.filterValue
+                                   sortAscending=controller.sortAscending
+                                   sortProperties=controller.sortProperties
+                                   columnSorted="sort"
+                                   columnFiltered="filter"}}
+          {{else}}
+            {{tb-helper "caption" column}}
+          {{/if}}
+        </th>
+      {{/each}}
+      <th>
+        <button type="btn" class="btn btn-sm btn-warning pull-right clear-filters" {{action "clearFilters"}}>{{t "buttons.clearFilters"}}</button>
+      </th>
+    </tr>
+  </thead>
+  <tbody>
+    {{#if history.length}}
+      {{#if model.length}}
+        {{#each item in this}}
+          {{job-tr-view job=item onStopJob="interruptJob" onFileRequested="loadFile"}}
+        {{/each}}
+      {{else}}
+        <tr>
+          <td colspan="5">
+            <h4 class="empty-list">{{t "emptyList.history.noMatches"}}</h4>
+          </td>
+        </tr>
+      {{/if}}
+    {{else}}
+      <tr>
+        <td colspan="5">
+          <h4 class="empty-list">{{t "emptyList.history.noItems"}}</h4>
+        </td>
+      </tr>
+    {{/if}}
+  </tbody>
+</table>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index.hbs
new file mode 100644
index 0000000..a06c330
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index.hbs
@@ -0,0 +1,110 @@
+{{!
+* 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.
+}}
+
+<div id="index-content">
+  <div class="main-content">
+    <aside {{bind-attr class="isDatabaseExplorerVisible:col-md-3:no-width :col-xs-3 :no-padding"}}>
+      {{render 'databases'}}
+    </aside>
+
+    <div {{bind-attr class="isDatabaseExplorerVisible:col-md-9:col-md-12 :col-xs-9 :query-container"}}>
+      {{#panel-widget headingTranslation="titles.query.editor" classNames="query-editor-panel" iconActions=queryPanelActions}}
+        {{render 'open-queries'}}
+
+        <div class="toolbox">
+          {{#if canExecute}}
+            <button type="button" class="btn btn-sm btn-success execute-query" {{action "executeQuery"}}>
+              {{t "buttons.execute"}}
+            </button>
+          {{else}}
+            <button type="button" {{bind-attr class=":btn :btn-sm :btn-warning model.isCancelling:disabled"}} {{action "stopCurrentJob"}}>
+              {{#if model.isCancelling}}
+                {{t "buttons.stoppingJob"}}
+                <div class="spinner small inline-spinner"></div>
+              {{else}}
+                {{t "buttons.stopJob"}}
+              {{/if}}
+            </button>
+          {{/if}}
+
+          <button type="button" {{bind-attr class=":btn :btn-sm :btn-default canExecute::disabled"}} {{action "explainQuery"}}>
+            {{t "buttons.explain"}}
+          </button>
+
+          <button type="button" class="btn btn-sm btn-default save-query-as" {{action "saveQuery"}}>{{t "buttons.saveAs"}}</button>
+
+          {{render 'insert-udfs'}}
+
+          {{#if canKillSession}}
+            <button type="button" class="btn btn-sm btn-danger kill-session" {{action "killSession"}}>{{t "buttons.killSession"}}</button>
+          {{/if}}
+
+          <button type="button" class="btn btn-sm btn-primary  pull-right" {{action "addQuery"}}>{{t "buttons.newQuery"}}</button>
+        </div>
+      {{/panel-widget}}
+
+      {{#if displayJobTabs}}
+        {{#if jobProgressService.currentJob.stages.length}}
+          {{#progress-widget value=jobProgressService.currentJob.totalProgress}}
+          {{/progress-widget}}
+        {{/if}}
+      {{/if}}
+
+      {{#if queryParams}}
+        {{#panel-widget headingTranslation="titles.query.parameters"}}
+          <div class="form-horizontal">
+            {{#each param in queryParams}}
+              <div {{bind-attr class=":form-group param.value:has-success:has-error"}}>
+                <label class="col-sm-3 control-label">{{param.name}}</label>
+                  <div class="col-sm-9">
+                    {{input value=param.value placeholder="value" class="form-control"}}
+                  </div>
+              </div>
+            {{/each}}
+          </div>
+        {{/panel-widget}}
+      {{/if}}
+
+      {{#if displayJobTabs}}
+        {{#panel-widget heading=queryProcessTitle
+                        isLoading=content.isRunning
+                        menuItems=downloadMenu
+                        menuHeadingTranslation="titles.download"
+                        classNames="query-process-results-panel"}}
+          {{#tabs-widget tabs=queryProcessTabs selectedTab=selectedQueryProcessTab}}
+            {{outlet}}
+          {{/tabs-widget}}
+        {{/panel-widget}}
+      {{/if}}
+    </div>
+  </div>
+
+  {{outlet 'overlay'}}
+
+  <div class="query-menu">
+    {{#popover-widget classNames="fa fa-info-circle queries-icon" titleTranslation="popover.queryEditorHelp.title" }}
+      <ul>
+        <li>{{t 'popover.queryEditorHelp.content.line1'}}</li>
+        <li>{{t 'popover.queryEditorHelp.content.line2'}}</li>
+        <li>{{t 'popover.queryEditorHelp.content.line3'}}</li>
+      </ul>
+    {{/popover-widget}}
+
+    {{render 'query-tabs'}}
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index/history-query/explain.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index/history-query/explain.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index/history-query/explain.hbs
new file mode 100644
index 0000000..3f8810f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index/history-query/explain.hbs
@@ -0,0 +1,23 @@
+{{!
+* 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.
+}}
+
+{{#each header in formattedExplain}}
+  {{#expander-widget heading=header.text}}
+    {{tree-view content=header.contents}}
+  {{/expander-widget}}
+{{/each}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index/history-query/logs.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index/history-query/logs.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index/history-query/logs.hbs
new file mode 100644
index 0000000..283d929
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index/history-query/logs.hbs
@@ -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.
+}}
+
+{{log-helper model.log}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index/history-query/results.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index/history-query/results.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index/history-query/results.hbs
new file mode 100644
index 0000000..2b7dae9
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/index/history-query/results.hbs
@@ -0,0 +1,56 @@
+{{!
+* 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.
+}}
+
+<div id="query-results">
+  {{#if results}}
+    <div class="query-results-tools">
+      {{extended-input type="text"
+                       class="pull-left input-sm form-control"
+                       placeholderTranslation='placeholders.search.results'
+                       valueChanged="filterResults"}}
+
+      <div class="pull-right">
+        <button type="button" {{action "getPreviousPage"}}
+                {{bind-attr class=":btn :btn-sm :btn-default disablePrevious:disabled"}}>{{t "buttons.previousPage"}}</button>
+        <button type="button" {{action "getNextPage"}}
+                {{bind-attr class=":btn :btn-sm :btn-default disableNext:disabled"}}>{{t "buttons.nextPage"}}</button>
+      </div>
+    </div>
+
+    <table class="table table-expandable">
+      <thead>
+        <tr>
+          {{#each column in formattedResults.columns}}
+            <th> {{column.name}} </th>
+          {{/each}}
+        </tr>
+      </thead>
+      <tbody>
+        {{#each row in formattedResults.rows}}
+          <tr>
+            {{#each item in row}}
+              <td>{{item}}</td>
+            {{/each}}
+          </tr>
+        {{/each}}
+      </tbody>
+    </table>
+  {{else}}
+    {{error}}
+  {{/if}}
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/insert-udfs.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/insert-udfs.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/insert-udfs.hbs
new file mode 100644
index 0000000..f01104b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/insert-udfs.hbs
@@ -0,0 +1,46 @@
+{{!
+* 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.
+}}
+
+{{#if this.length}}
+  <div class="dropdown insert-udfs">
+    <a role="button" data-toggle="dropdown" class="btn btn-default btn-sm" data-target="#">
+      {{t "placeholders.select.udfs"}}
+      <span class="caret"></span>
+    </a>
+    <ul class="dropdown-menu pull-right" role="menu" aria-labelledby="dropdownMenu">
+      {{#each item in this}}
+        <li class="dropdown dropdown-submenu">
+          {{#if item.file}}
+            <a tabindex="-1">{{item.file.name}}</a>
+          {{else}}
+            <a tabindex="-1">{{tb-helper item.name}}</a>
+          {{/if}}
+          <ul class="dropdown-menu">
+            {{#each udf in item.udfs}}
+              <li>
+                {{#no-bubbling click="insertUdf" data=udf tagName="a"}}
+                  {{udf.name}}
+                {{/no-bubbling}}
+              </li>
+            {{/each}}
+          </ul>
+        </li>
+      {{/each}}
+    </ul>
+  </div>
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/loading.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/loading.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/loading.hbs
new file mode 100644
index 0000000..c0de275
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/loading.hbs
@@ -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.
+}}
+
+<div class="spinner"></div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/logs.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/logs.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/logs.hbs
new file mode 100644
index 0000000..283d929
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/logs.hbs
@@ -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.
+}}
+
+{{log-helper model.log}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/message.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/message.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/message.hbs
new file mode 100644
index 0000000..ad7fb9a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/message.hbs
@@ -0,0 +1,36 @@
+{{!
+* 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.
+}}
+
+<div {{bind-attr class=":alert :notification view.typeClass"}}>
+  <button type="button" class="close" {{action "close" target="view"}}><span aria-hidden="true">&times;</span></button>
+  <i {{bind-attr class=":fa view.typeIcon"}}></i>
+
+  {{#if view.notification.body}}
+    <a {{action "expand" target="view"}}>
+      {{view.notification.message}}
+    </a>
+  {{else}}
+      {{view.notification.message}}
+  {{/if}}
+
+  {{#if view.isExpanded}}
+  <pre class="message-body">
+    {{preformatted-string view.notification.body}}
+  </pre>
+  {{/if}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/messages.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/messages.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/messages.hbs
new file mode 100644
index 0000000..3dfc7d0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/messages.hbs
@@ -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.
+}}
+
+<div id="messages" class="index-overlay">
+  {{#panel-widget headingTranslation="titles.query.messages"}}
+    <div class="messages-controls">
+      {{#if messages.length}}
+        <button class="btn btn-danger btn-xs" {{action 'removeAllMessages'}}><i class="fa fa-minus"></i> Clear All</button>
+      {{/if}}
+    </div>
+
+
+    {{#each message in messages}}
+      {{view 'message' notification=message}}
+    {{/each}}
+  {{/panel-widget}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/modal-delete.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/modal-delete.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/modal-delete.hbs
new file mode 100644
index 0000000..032c144
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/modal-delete.hbs
@@ -0,0 +1,21 @@
+{{!
+* 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.
+}}
+
+{{#modal-widget heading=heading close="close" ok="delete"}}
+  {{tb-helper text}}
+{{/modal-widget}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/modal-save-query.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/modal-save-query.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/modal-save-query.hbs
new file mode 100644
index 0000000..6853550
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/modal-save-query.hbs
@@ -0,0 +1,24 @@
+{{!
+* 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.
+}}
+
+{{#modal-widget heading=heading close="close" ok="save"}}
+  {{input type="text" class="form-control" value=text }}
+  {{#if showMessage}}
+    <span class="label label-warning">{{tb-helper message}}</span>
+  {{/if}}
+{{/modal-widget}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/modal-save.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/modal-save.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/modal-save.hbs
new file mode 100644
index 0000000..8d83f2b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/modal-save.hbs
@@ -0,0 +1,21 @@
+{{!
+* 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.
+}}
+
+{{#modal-widget heading=heading close="close" ok="save"}}
+  {{input type=type class="form-control"  value=text }}
+{{/modal-widget}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/notification.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/notification.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/notification.hbs
new file mode 100644
index 0000000..35c2fe1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/notification.hbs
@@ -0,0 +1,23 @@
+{{!
+* 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.
+}}
+
+<div {{bind-attr class=":alert :notification view.typeClass"}}>
+  <button type="button" class="close" {{action "close" target="view"}}><span aria-hidden="true">&times;</span></button>
+  <i {{bind-attr class=":fa view.typeIcon"}}></i>
+  {{view.notification.message}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/open-queries.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/open-queries.hbs b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/open-queries.hbs
new file mode 100644
index 0000000..6d6f0dc
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/templates/open-queries.hbs
@@ -0,0 +1,23 @@
+{{!
+* 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.
+}}
+
+{{#tabs-widget tabs=queryTabs removeClicked="removeQueryTab" canRemove=true onActiveTitleClick="changeTabTitle"}}
+  {{outlet 'overlay'}}
+  {{query-editor tables=selectedTables query=currentQuery.fileContent editor=view.editor highlightedText=highlightedText
+                 columnsNeeded="getColumnsForAutocomplete"}}
+{{/tabs-widget}}


[21/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/deploy_store_app/deploy_store_app_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/deploy_store_app/deploy_store_app_view.js b/ambari-web/app/views/main/assemblies/deploy_store_app/deploy_store_app_view.js
new file mode 100644
index 0000000..cf0b91c
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/deploy_store_app/deploy_store_app_view.js
@@ -0,0 +1,62 @@
+/**
+ * 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 = require('app');
+var validator = require('utils/validator');
+
+App.DeployStoreAppView = Em.View.extend({
+
+  templateName: require('templates/main/assemblies/deploy_store_app/config'),
+
+  config: null,
+
+  observeDisable: function() {
+    this.get('parentView').$('.sliderBar').slider('option', 'disabled', this.get('isDeploying'));
+  }.observes('isDeploying'),
+
+  didInsertElement: function() {
+    this.$('.sliderBar').slider({
+      step: this.get('config.step'),
+      min: this.get('config.minValue'),
+      max: this.get('config.maxValue'),
+      value: this.get('config.defaultValue'),
+      slide: function( event, ui ) {
+        this.set('config.value', ui.value);
+        this.set('config.errorMessage', '');
+      }.bind(this)
+    });
+  },
+
+  sliderInputView: Em.TextField.extend({
+    disabled: Em.computed.alias('parentView.isDeploying'),
+    keyUp: function() {
+      if (validator.isValidInt(this.get('value'))) {
+        if (this.get('value') > this.get('parentView.config.maxValue')) {
+          this.set('value', this.get('parentView.config.maxValue'));
+        } else if (this.get('value') < this.get('parentView.config.minValue')) {
+          this.set('value', this.get('parentView.config.minValue'));
+        }
+        this.get('parentView').$('.sliderBar').slider('value', this.get('value'));
+        this.set('parentView.config.errorMessage', '');
+      } else {
+        this.set('parentView.config.errorMessage', Em.I18n.t('errorMessage.config.number.integer'));
+      }
+    }
+  })
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/service_groups/configs_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/service_groups/configs_view.js b/ambari-web/app/views/main/assemblies/service_groups/configs_view.js
new file mode 100644
index 0000000..65318cb
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/service_groups/configs_view.js
@@ -0,0 +1,25 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesServiceGroupConfigsView = Em.View.extend({
+
+  templateName: require('templates/main/assemblies/service_groups/configs')
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/service_groups/detailed_info_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/service_groups/detailed_info_view.js b/ambari-web/app/views/main/assemblies/service_groups/detailed_info_view.js
new file mode 100644
index 0000000..c6ed246
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/service_groups/detailed_info_view.js
@@ -0,0 +1,25 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesServiceGroupDetailedInfoView = Em.View.extend({
+
+  templateName: require('templates/main/assemblies/service_groups/detailed_info')
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/service_groups/menu_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/service_groups/menu_view.js b/ambari-web/app/views/main/assemblies/service_groups/menu_view.js
new file mode 100644
index 0000000..f9e0932
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/service_groups/menu_view.js
@@ -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.
+ */
+
+var App = require('app');
+
+App.MainAssembliesServiceGroupMenuView = Em.View.extend({
+
+  templateName: require('templates/main/assemblies/service_groups/menu'),
+
+  menu: function () {
+    var currentPath = App.get('router.currentState.path');
+    return [
+      {title: Em.I18n.t('common.summary'), route: 'summary', isActive: currentPath.endsWith('summary')},
+      {title: Em.I18n.t('common.settings'), route: 'settings', isActive: currentPath.endsWith('settings')},
+      {title: Em.I18n.t('assemblies.serviceGroups.menu.detailedInfo'), route: 'detailedInfo', isActive: currentPath.endsWith('detailedInfo')}
+    ];
+  }.property('App.router.currentState.path'),
+
+  didInsertElement: function () {
+    App.tooltip(this.$("[rel='assembly-file-link']"));
+  },
+
+  willDestroyElement: function () {
+    this.$("[rel='assembly-file-link']").tooltip('destroy');
+  },
+
+  /**
+   * @param {{context: string}} event
+   */
+  moveTo: function (event) {
+    var route = event.context;
+    this.get('controller.target').transitionTo(route);
+  }
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/service_groups/service_group_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/service_groups/service_group_view.js b/ambari-web/app/views/main/assemblies/service_groups/service_group_view.js
new file mode 100644
index 0000000..b42b46f
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/service_groups/service_group_view.js
@@ -0,0 +1,25 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesServiceGroupView = Em.View.extend({
+
+  templateName: require('templates/main/assemblies/service_groups/service_group')
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/service_groups/summary_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/service_groups/summary_view.js b/ambari-web/app/views/main/assemblies/service_groups/summary_view.js
new file mode 100644
index 0000000..d3ecf04
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/service_groups/summary_view.js
@@ -0,0 +1,186 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesServiceGroupSummaryView = Em.View.extend({
+
+  templateName: require('templates/main/assemblies/service_groups/summary'),
+
+  /**
+   * Contain array with list of master components from <code>App.Service.hostComponets</code> which are
+   * <code>App.HostComponent</code> models.
+   *
+   * @type {App.HostComponent[]}
+   */
+  mastersObj: [],
+  mastersLength: 0,
+
+  /**
+   * Contain array with list of slave components models <code>App.SlaveComponent</code>.
+   *
+   * @type {App.SlaveComponent[]}
+   */
+  slavesObj: [],
+  slavesLength: 0,
+
+  /**
+   * Contain array with list of client components models <code>App.ClientComponent</code>.
+   *
+   * @type {App.ClientComponent[]}
+   */
+  clientObj: [],
+  clientsLength: 0,
+
+  /**
+   * Show spinner while components are loading
+   *
+   * @type {boolean}
+   * @default true
+   */
+  showSpinner: true,
+
+  didInsertElement: function() {
+    var services = this.get('controller.content.services');
+    if (services.content.length) {
+      this.set('controller.activeService', services.objectAt(0));
+    }
+    var shownServices = this.get('controller.content.services').map(function(_service, index) {
+      return Em.Object.create({
+        id:  _service.get('id'),
+        displayName: _service.get('displayName'),
+        url: _service.get('logo'),
+        isActive: !!index
+      });
+    });
+    this.set('shownServices', shownServices);
+    this.set('activeService', shownServices.objectAt(0));
+  },
+
+  willDestroyElement: function() {
+    this.get('mastersObj').clear();
+    this.get('slavesObj').clear();
+    this.get('clientObj').clear();
+  },
+
+
+  /**
+   * Show services icons
+   *
+   * @type {{displayName: string, url: string}[]}
+   */
+  shownServices: [],
+
+  /**
+   * {{context: App.ServiceGroup}} @param event
+   */
+  makeServiceActive: function(event) {
+    var service = event.context;
+    var controller= this.get('controller');
+    service.set('isActive', true);
+    this.set('activeService', service);
+  },
+
+  setActiveService: function() {
+    var activeService = this.get('activeService');
+    var services = this.get('shownServices');
+    services.forEach(function(item) {
+      item.set('isActive', activeService.get('id') === item.get('id'));
+    });
+  }.observes('activeService'),
+
+
+  serviceSummaryView: Em.View.extend(App.MainDashboardServiceViewWrapper, {
+    templateName: 'templates/main/service/info/summary/base',
+    isFullWidth: true
+  }),
+
+  componentsLengthDidChange: function() {
+    var self = this;
+    var service = this.get('controller.activeService');
+    if (!service || service.get('deleteInProgress')) return;
+    Em.run.once(self, 'setComponentsContent');
+  }.observes('activeService','activeService.hostComponents.length', 'activeService.slaveComponents.@each.totalCount', 'activeService.clientComponents.@each.totalCount'),
+
+  setComponentsContent: function() {
+    Em.run.next(function() {
+      var activeService = this.get('activeService');
+
+      var service = App.Service.find().findProperty('id',activeService.get('id'));
+      if (Em.isNone(service)) {
+        return;
+      }
+
+      var masters = service.get('hostComponents').filterProperty('isMaster');
+      var slaves = service.get('slaveComponents').toArray();
+      var clients = service.get('clientComponents').toArray();
+
+      this.get('mastersObj').clear();
+      this.get('slavesObj').clear();
+      this.get('clientObj').clear();
+      this.updateComponentList(this.get('mastersObj'), masters);
+      this.updateComponentList(this.get('slavesObj'), slaves);
+      this.updateComponentList(this.get('clientObj'), clients);
+      this.set('showSpinner', !(masters.length || slaves.length || clients.length));
+
+    }.bind(this));
+  },
+
+  updateComponentList: function(source, data) {
+    var sourceIds = source.mapProperty('id');
+    var dataIds = data.mapProperty('id');
+    if (!sourceIds.length) {
+      source.pushObjects(data);
+    }
+    if (source.length > data.length) {
+      sourceIds.forEach(function(item, index) {
+        if (!dataIds.contains(item)) {
+          source.removeAt(index);
+        }
+      });
+    }
+    else {
+      if (source.length < data.length) {
+        dataIds.forEach(function (item, index) {
+          if (!sourceIds.contains(item)) {
+            source.pushObject(data.objectAt(index));
+          }
+        });
+      }
+    }
+  },
+
+  /**
+   * Open another browser window with assembly file content highlighted with highlight.js
+   */
+  showAssemblyFile: function () {
+    var assemblyFile = this.get('controller.content.assemblyFile');
+    var assemblyFileContent = '';
+    try {
+      assemblyFileContent = JSON.stringify(JSON.parse(assemblyFile), null, 2);
+    }
+    catch(e) {
+      assemblyFileContent = assemblyFile;
+    }
+    var newwindow = window.open();
+    var newdocument = newwindow.document;
+    newdocument.write('<head><link rel="stylesheet" href="stylesheets/vendor.css"></head><body><pre>' + hljs.highlight('json', assemblyFileContent).value + '</pre></body>');
+    newdocument.close();
+  }
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/service_groups_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/service_groups_view.js b/ambari-web/app/views/main/assemblies/service_groups_view.js
new file mode 100644
index 0000000..e5e1356
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/service_groups_view.js
@@ -0,0 +1,23 @@
+/**
+ * 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 = require('app');
+
+App.MainAssembliesServiceGroupsView = Em.View.extend({
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies/store_app_block_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies/store_app_block_view.js b/ambari-web/app/views/main/assemblies/store_app_block_view.js
new file mode 100644
index 0000000..9e95c74
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies/store_app_block_view.js
@@ -0,0 +1,82 @@
+/**
+ * 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 = require('app');
+
+/**
+ * Usage in the templates:
+ * <pre>
+ *   {{view App.StoreAppBlockView storeAppBinding="storeApp"}}
+ * </pre>
+ *
+ * @type {Em.View}
+ */
+App.StoreAppBlockView = Em.View.extend({
+
+  classNames: ['store-app-block-view'],
+
+  classNameBindings: ['storeApp.isActive:active'],
+
+  templateName: require('templates/main/assemblies/store_app_block'),
+
+  /**
+   * Bound from template
+   *
+   * @type {App.StoreApp}
+   */
+  storeApp: null,
+
+  /**
+   * Coma-separated list of the category names that App belongs to
+   *
+   * @type {string}
+   */
+  categoryNames: function () {
+    return this.get('storeApp.storeCategories').mapProperty('name').join(', ');
+  }.property('storeApp.storeCategories.@each.name'),
+
+  /**
+   * Show only two first services for App
+   *
+   * @type {string}
+   */
+  shownServices: function () {
+    return this.get('storeApp.services') ? this.get('storeApp.services').substring(0, 19) : '';
+  }.property('storeApp.services'),
+
+  /**
+   * Should be '...' shown for services
+   * true - if App belongs to more services
+   * false - otherwise
+   *
+   * @type {boolean}
+   */
+  moreServices: Em.computed.gt('storeApp.services.length', 19),
+
+  /**
+   * Should be double-pane shown for App
+   * true - if App belongs to more than one service
+   * false - otherwise
+   *
+   * @type {boolean}
+   */
+  showBgBlock: function () {
+    return this.get('storeApp.services') ? this.get('storeApp.services').split('|').length > 1 : false;
+  }.property('storeApp.services.[]'),
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/assemblies_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/assemblies_view.js b/ambari-web/app/views/main/assemblies_view.js
new file mode 100644
index 0000000..ca289b8
--- /dev/null
+++ b/ambari-web/app/views/main/assemblies_view.js
@@ -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.
+ */
+
+var App = require('app');
+
+App.MainAssembliesView = Em.View.extend({
+
+  templateName: require('templates/main/assemblies'),
+
+  didInsertElement: function () {
+    App.loadTimer.finish('App Store Page');
+  }
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/dashboard.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/dashboard.js b/ambari-web/app/views/main/dashboard.js
index 9694774..61b756c 100644
--- a/ambari-web/app/views/main/dashboard.js
+++ b/ambari-web/app/views/main/dashboard.js
@@ -22,6 +22,9 @@ App.MainDashboardView = Em.View.extend({
 
   name: 'mainDashboardView',
   templateName: require('templates/main/dashboard'),
+  didInsertElement: function() {
+
+  },
 
   selectedBinding: 'controller.selectedCategory',
   categories: [

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/menu.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/menu.js b/ambari-web/app/views/main/menu.js
index 8f6b14e..6cb427d 100644
--- a/ambari-web/app/views/main/menu.js
+++ b/ambari-web/app/views/main/menu.js
@@ -38,6 +38,7 @@ App.MainMenuView = Em.CollectionView.extend({
         if (!App.get('isOnlyViewUser')) {
           result.push(
               {label: Em.I18n.t('menu.item.dashboard'), routing: 'dashboard', active: 'active'},
+              {label: Em.I18n.t('menu.item.appStore'), routing: 'assemblies'},
               {label: Em.I18n.t('menu.item.services'), routing: 'services'},
               {label: Em.I18n.t('menu.item.hosts'), routing: 'hosts'},
               {label: Em.I18n.t('menu.item.alerts'), routing: 'alerts'}
@@ -65,13 +66,13 @@ App.MainMenuView = Em.CollectionView.extend({
 
     active: function () {
       if (App.get('clusterName') && App.router.get('clusterController.isLoaded')) {
-        var last_url = App.router.location.lastSetURL || location.href.replace(/^[^#]*#/, '');
-        if (last_url.substr(1, 4) !== 'main' || !this._childViews) {
+        var lastUrl = App.router.location.lastSetURL || location.href.replace(/^[^#]*#/, '');
+        if (lastUrl.substr(1, 4) !== 'main' || !this._childViews) {
           return;
         }
         var reg = /^\/main\/([a-z]+)/g;
-        var sub_url = reg.exec(last_url);
-        var chunk = (null != sub_url) ? sub_url[1] : 'dashboard';
+        var subUrl = reg.exec(lastUrl);
+        var chunk = (null != subUrl) ? subUrl[1] : 'dashboard';
         return this.get('content.routing').indexOf(chunk) === 0 ? "active" : "";
       }
       return "";
@@ -103,7 +104,7 @@ App.MainMenuView = Em.CollectionView.extend({
       var itemName = this.get('content').routing;
       var categories = [];
       // create dropdown categories for each menu item
-      if (itemName == 'admin') {
+      if (itemName === 'admin') {
         categories = [];
         if(App.isAuthorized('CLUSTER.VIEW_STACK_DETAILS, CLUSTER.UPGRADE_DOWNGRADE_STACK') || (App.get('upgradeInProgress') || App.get('upgradeHolding'))) {
           categories.push({
@@ -112,7 +113,7 @@ App.MainMenuView = Em.CollectionView.extend({
             label: Em.I18n.t('admin.stackUpgrade.title')
           });
         }
-        if(App.isAuthorized('AMBARI.SET_SERVICE_USERS_GROUPS') ||  (App.get('upgradeInProgress') || App.get('upgradeHolding'))) {
+        if(App.isAuthorized('AMBARI.SET_SERVICE_USERS_GROUPS') ||  App.get('upgradeInProgress') || App.get('upgradeHolding')) {
           categories.push({
             name: 'adminServiceAccounts',
             url: 'serviceAccounts',
@@ -126,7 +127,7 @@ App.MainMenuView = Em.CollectionView.extend({
             label: Em.I18n.t('common.kerberos')
           });
         }
-        if (App.isAuthorized('SERVICE.START_STOP, CLUSTER.MODIFY_CONFIGS') || (App.get('upgradeInProgress') || App.get('upgradeHolding'))) {
+        if (App.isAuthorized('SERVICE.START_STOP, CLUSTER.MODIFY_CONFIGS') || App.get('upgradeInProgress') || App.get('upgradeHolding')) {
           if (App.supports.serviceAutoStart) {
             categories.push({
               name: 'serviceAutoStart',
@@ -137,7 +138,7 @@ App.MainMenuView = Em.CollectionView.extend({
         }
       }
       return categories;
-    }.property(''),
+    }.property(),
 
     AdminDropdownItemView: Ember.View.extend({
       tagName: 'li',

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/service/all_services_actions.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/all_services_actions.js b/ambari-web/app/views/main/service/all_services_actions.js
index b0aa99c..1a22934 100644
--- a/ambari-web/app/views/main/service/all_services_actions.js
+++ b/ambari-web/app/views/main/service/all_services_actions.js
@@ -18,9 +18,38 @@
 
 var App = require('app');
 
+/**
+ * Check serviceGroup's <code>dependentKey</code>
+ * If there is no serviceGroup, it means that view is used for the whole cluster and all service groups should be checked
+ *
+ * @param {string} dependentKey
+ * @returns {Ember.ComputedProperty}
+ */
+function serviceGroupBased(dependentKey) {
+  var key1 = 'serviceGroup.' + dependentKey;
+  var key2 = 'serviceController.content.@each.' + dependentKey;
+  return Ember.computed(key1, key2, function () {
+    var serviceGroup = this.get('serviceGroup');
+    if (!serviceGroup) {
+      return this.get('serviceController.content').everyProperty(dependentKey, true);
+    }
+    return serviceGroup.get(dependentKey);
+  });
+}
+
+/**
+ * List of actions like "Start All", "Stop All" etc
+ * Used for service groups and whole cluster
+ *
+ * @type {Em.View}
+ */
 App.AllServicesActionView = Em.View.extend({
   templateName: require('templates/main/service/all_services_actions'),
 
+  isStopAllDisabled: serviceGroupBased('isStopAllDisabled'),
+  isStartAllDisabled: serviceGroupBased('isStartAllDisabled'),
+  isRestartAllRequiredDisabled: serviceGroupBased('isRestartAllRequiredDisabled'),
+
   serviceController: function () {
     return App.get('router.mainServiceController');
   }.property('App.router.mainServiceController')

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/service/info/summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/info/summary.js b/ambari-web/app/views/main/service/info/summary.js
index 6191e6a..9c987b8 100644
--- a/ambari-web/app/views/main/service/info/summary.js
+++ b/ambari-web/app/views/main/service/info/summary.js
@@ -357,7 +357,9 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, App.TimeRangeMixin
     var self = this,
         stackService = App.StackService.find(this.get('controller.content.serviceName'));
 
-    if (!graphNames && !stackService.get('isServiceWithWidgets')) {
+    var isAssembly = this.get('controller.content.serviceGroupName') !== 'CORE';
+
+    if ((!graphNames && !stackService.get('isServiceWithWidgets')) || isAssembly) {
       this.get('serviceMetricGraphs').clear();
       this.set('isServiceMetricLoaded', false);
       return;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/service/item.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/item.js b/ambari-web/app/views/main/service/item.js
index 36b3413..b1913cd 100644
--- a/ambari-web/app/views/main/service/item.js
+++ b/ambari-web/app/views/main/service/item.js
@@ -318,13 +318,20 @@ App.MainServiceItemView = Em.View.extend({
     return this.get('state') !== 'inDOM' || this.get('maintenance').length !== 0;
   }.property('maintenance'),
 
+  isServiceActionsVisible: function() {
+    var isCore = App.get('router.mainServiceController.serviceGroup.id') === 'CORE';
+    return this.get('isMaintenanceActive') && isCore;
+  }.property('isMaintenanceActive', 'controller.content.serviceName'),
+
   hasConfigTab: function() {
-    return App.isAuthorized('CLUSTER.VIEW_CONFIGS', {ignoreWizard: true}) && !App.get('services.noConfigTypes').contains(this.get('controller.content.serviceName'));
-  }.property('controller.content.serviceName','App.services.noConfigTypes'),
+    var isCore = App.get('router.mainServiceController.serviceGroup.id') === 'CORE';
+    return App.isAuthorized('CLUSTER.VIEW_CONFIGS', {ignoreWizard: true}) && isCore && !App.get('services.noConfigTypes').contains(this.get('controller.content.serviceName'));
+  }.property('controller.content.serviceName','App.services.noConfigTypes', 'App.router.mainServiceController.serviceGroup'),
 
   hasHeatmapTab: function() {
-    return App.get('services.servicesWithHeatmapTab').contains(this.get('controller.content.serviceName'));
-  }.property('controller.content.serviceName', 'App.services.servicesWithHeatmapTab'),
+    var isCore = App.get('router.mainServiceController.serviceGroup.id') === 'CORE';
+    return isCore && App.get('services.servicesWithHeatmapTab').contains(this.get('controller.content.serviceName'));
+  }.property('controller.content.serviceName', 'App.services.servicesWithHeatmapTab', 'App.router.mainServiceController.serviceGroup'),
 
   didInsertElement: function () {
     this.get('controller').setStartStopState();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/service/menu.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/menu.js b/ambari-web/app/views/main/service/menu.js
index f5768f8..9cb0033 100644
--- a/ambari-web/app/views/main/service/menu.js
+++ b/ambari-web/app/views/main/service/menu.js
@@ -17,15 +17,14 @@
  */
 
 var App = require('app');
+var misc = require('utils/misc');
 
 App.MainServiceMenuView = Em.CollectionView.extend({
-  disabledServices: [],
 
   content: function () {
-    return App.router.get('mainServiceController.content').filter(function(item){
-      return !this.get('disabledServices').contains(item.get('id'));
-    }, this);
-  }.property('App.router.mainServiceController.content', 'App.router.mainServiceController.content.length'),
+    var serviceGroup = this.get('serviceGroup');
+    return serviceGroup ? misc.sortByOrder(App.StackService.find().mapProperty('serviceName'), serviceGroup.get('services').toArray()) : [];
+  }.property('serviceGroup'),
 
   didInsertElement:function () {
     App.router.location.addObserver('lastSetURL', this, 'renderOnRoute');
@@ -38,20 +37,20 @@ App.MainServiceMenuView = Em.CollectionView.extend({
     this.$(".restart-required-service").tooltip('destroy');
   },
 
-  activeServiceId:null,
+  activeServiceId: null,
 
   /**
    *    Syncs navigation menu with requested URL
    */
   renderOnRoute:function () {
-    var last_url = App.router.location.lastSetURL || location.href.replace(/^[^#]*#/, '');
-    if (last_url.substr(1, 4) !== 'main' || !this._childViews) {
+    var lastUrl = App.router.location.lastSetURL || location.href.replace(/^[^#]*#/, '');
+    if (lastUrl.substr(1, 4) !== 'main' || !this._childViews) {
       return;
     }
     var reg = /^\/main\/services\/(\S+)\//g;
-    var sub_url = reg.exec(last_url);
-    var service_id = (null != sub_url) ? sub_url[1] : 1;
-    this.set('activeServiceId', service_id);
+    var subUrl = reg.exec(lastUrl);
+    var serviceId = null != subUrl ? subUrl[1] : 1;
+    this.set('activeServiceId', serviceId);
   },
 
   tagName:'ul',
@@ -59,15 +58,15 @@ App.MainServiceMenuView = Em.CollectionView.extend({
 
   itemViewClass:Em.View.extend({
 
-    classNameBindings:["active", "clients"],
-    templateName:require('templates/main/service/menu_item'),
+    classNameBindings: ["active", "clients"],
+    templateName: require('templates/main/service/menu_item'),
     restartRequiredMessage: null,
 
     shouldBeRestarted: Em.computed.someBy('content.hostComponents', 'staleConfigs', true),
 
     active:function () {
       return this.get('content.id') == this.get('parentView.activeServiceId') ? 'active' : '';
-    }.property('parentView.activeServiceId'),
+    }.property('content.id', 'parentView.activeServiceId'),
 
     alertsCount: function () {
       return this.get('content.alertsCount') > 99 ? "99+" : this.get('content.alertsCount') ;
@@ -79,39 +78,33 @@ App.MainServiceMenuView = Em.CollectionView.extend({
       return !App.get('services.noConfigTypes').contains(this.get('content.serviceName'));
     }.property('App.services.noConfigTypes','content.serviceName'),
 
-    link: function() {
-      var stateName = (['summary','configs'].contains(App.router.get('currentState.name')))
-        ? this.get('isConfigurable') && this.get('parentView.activeServiceId') != this.get('content.id') ?  App.router.get('currentState.name') : 'summary'
-        : 'summary';
-      return "#/main/services/" + this.get('content.id') + "/" + stateName;
-    }.property('App.router.currentState.name', 'parentView.activeServiceId', 'isConfigurable'),
-
     goToConfigs: function () {
       App.router.set('mainServiceItemController.routeToConfigs', true);
       App.router.transitionTo('services.service.configs', this.get('content'));
       App.router.set('mainServiceItemController.routeToConfigs', false);
     },
 
+    link: function() {
+      if (this.get('controller.name') && this.get('controller.name') == "mainAssembliesController" ) {
+        return "javascript: void(0)";
+      }
+      var stateName = (['summary','configs'].contains(App.router.get('currentState.name')))
+        ? this.get('isConfigurable') && this.get('parentView.activeServiceId') != this.get('content.id') ?  App.router.get('currentState.name') : 'summary' : 'summary';
+      return "#/main/services/" + this.get('content.id') + "/" + stateName;
+    }.property('App.router.currentState.name', 'parentView.activeServiceId', 'isConfigurable'),
+
     refreshRestartRequiredMessage: function() {
       var restarted, componentsCount, hostsCount, message, tHosts, tComponents;
       restarted = this.get('content.restartRequiredHostsAndComponents');
       componentsCount = 0;
       hostsCount = 0;
-      message = "";
+      message = '';
       for (var host in restarted) {
         hostsCount++;
         componentsCount += restarted[host].length;
       }
-      if (hostsCount > 1) {
-        tHosts = Em.I18n.t('common.hosts');
-      } else {
-        tHosts = Em.I18n.t('common.host');
-      }
-      if (componentsCount > 1) {
-        tComponents = Em.I18n.t('common.components');
-      } else {
-        tComponents = Em.I18n.t('common.component');
-      }
+      tHosts = hostsCount > 1 ? Em.I18n.t('common.hosts') : Em.I18n.t('common.host');
+      tComponents = componentsCount > 1 ? Em.I18n.t('common.components') : Em.I18n.t('common.component');
       message += componentsCount + ' ' + tComponents + ' ' + Em.I18n.t('on') + ' ' +
         hostsCount + ' ' + tHosts + ' ' + Em.I18n.t('services.service.config.restartService.needToRestartEnd');
       this.set('restartRequiredMessage', message);
@@ -121,13 +114,14 @@ App.MainServiceMenuView = Em.CollectionView.extend({
 });
 
 App.TopNavServiceMenuView = Em.CollectionView.extend({
-  disabledServices: [],
 
   content: function () {
-    return App.router.get('mainServiceController.content').filter(function (item) {
-      return !this.get('disabledServices').contains(item.get('id'));
-    }, this);
-  }.property('App.router.mainServiceController.content', 'App.router.mainServiceController.content.length'),
+    if (!App.router.get('clusterController.isLoaded')) {
+      return [];
+    }
+    var serviceGroup = App.ServiceGroup.find('CORE');
+    return misc.sortByOrder(App.StackService.find().mapProperty('serviceName'), serviceGroup.get('services').toArray());
+  }.property('App.router.clusterController.isLoaded'),
 
   didInsertElement:function () {
     App.router.location.addObserver('lastSetURL', this, 'renderOnRoute');
@@ -145,14 +139,14 @@ App.TopNavServiceMenuView = Em.CollectionView.extend({
    *    Syncs navigation menu with requested URL
    */
   renderOnRoute:function () {
-    var last_url = App.router.location.lastSetURL || location.href.replace(/^[^#]*#/, '');
-    if (last_url.substr(1, 4) !== 'main' || !this._childViews) {
+    var lastUrl = App.router.location.lastSetURL || location.href.replace(/^[^#]*#/, '');
+    if (lastUrl.substr(1, 4) !== 'main' || !this._childViews) {
       return;
     }
     var reg = /^\/main\/services\/(\S+)\//g;
-    var sub_url = reg.exec(last_url);
-    var service_id = (null != sub_url) ? sub_url[1] : 1;
-    this.set('activeServiceId', service_id);
+    var subUrl = reg.exec(lastUrl);
+    var serviceId = null != subUrl ? subUrl[1] : 1;
+    this.set('activeServiceId', serviceId);
   },
 
   tagName:'ul',
@@ -179,8 +173,8 @@ App.TopNavServiceMenuView = Em.CollectionView.extend({
     }.property('App.services.noConfigTypes','content.serviceName'),
 
     link: function() {
-      var stateName = (['summary','configs'].contains(App.router.get('currentState.name')))
-        ? this.get('isConfigurable') ?  App.router.get('currentState.name') : 'summary'
+      var stateName = ['summary','configs'].contains(App.router.get('currentState.name'))
+        ? this.get('isConfigurable') ? App.router.get('currentState.name') : 'summary'
         : 'summary';
       return "#/main/services/" + this.get('content.id') + "/" + stateName;
     }.property('App.router.currentState.name', 'parentView.activeServiceId','isConfigurable'),
@@ -196,21 +190,13 @@ App.TopNavServiceMenuView = Em.CollectionView.extend({
       restarted = this.get('content.restartRequiredHostsAndComponents');
       componentsCount = 0;
       hostsCount = 0;
-      message = "";
+      message = '';
       for (var host in restarted) {
         hostsCount++;
         componentsCount += restarted[host].length;
       }
-      if (hostsCount > 1) {
-        tHosts = Em.I18n.t('common.hosts');
-      } else {
-        tHosts = Em.I18n.t('common.host');
-      }
-      if (componentsCount > 1) {
-        tComponents = Em.I18n.t('common.components');
-      } else {
-        tComponents = Em.I18n.t('common.component');
-      }
+      tHosts = hostsCount > 1 ? Em.I18n.t('common.hosts') : Em.I18n.t('common.host');
+      tComponents = componentsCount > 1 ? Em.I18n.t('common.components') : Em.I18n.t('common.component');
       message += componentsCount + ' ' + tComponents + ' ' + Em.I18n.t('on') + ' ' +
         hostsCount + ' ' + tHosts + ' ' + Em.I18n.t('services.service.config.restartService.needToRestartEnd');
       this.set('restartRequiredMessage', message);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/app/views/main/service/widgets/create/expression_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/widgets/create/expression_view.js b/ambari-web/app/views/main/service/widgets/create/expression_view.js
index 32c664f..d48cdb3 100644
--- a/ambari-web/app/views/main/service/widgets/create/expression_view.js
+++ b/ambari-web/app/views/main/service/widgets/create/expression_view.js
@@ -116,7 +116,7 @@ App.WidgetWizardExpressionView = Em.View.extend({
   redrawField: function () {
     this.set('expression.data', misc.sortByOrder($(this.get('element')).find('.metric-instance').map(function () {
       return this.id;
-    }), this.get('expression.data')));
+    }), this.get('expression.data'), 'id'));
   },
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/config.coffee
----------------------------------------------------------------------
diff --git a/ambari-web/config.coffee b/ambari-web/config.coffee
index 6ed0915..8d44244 100644
--- a/ambari-web/config.coffee
+++ b/ambari-web/config.coffee
@@ -68,7 +68,8 @@ exports.config =
           'vendor/scripts/spin.js',
           'vendor/scripts/jquery.flexibleArea.js',
           'vendor/scripts/FileSaver.js',
-          'vendor/scripts/Blob.js'
+          'vendor/scripts/Blob.js',
+          'vendor/scripts/highlight.pack.js'
 
           ]
 
@@ -88,7 +89,8 @@ exports.config =
           'vendor/styles/bootstrap-checkbox.css',
           'vendor/styles/bootstrap-slider.min.css',
           'vendor/styles/bootstrap-switch.min.css',
-          'vendor/styles/visualsearch-datauri.css'
+          'vendor/styles/visualsearch-datauri.css',
+          'vendor/styles/highlight.css'
         ],
         after: ['app/styles/custom-ui.css']
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/test/controllers/global/update_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/update_controller_test.js b/ambari-web/test/controllers/global/update_controller_test.js
index dc57a57..d44f155 100644
--- a/ambari-web/test/controllers/global/update_controller_test.js
+++ b/ambari-web/test/controllers/global/update_controller_test.js
@@ -59,7 +59,7 @@ describe('App.UpdateController', function () {
 
     it('isWorking = true', function () {
       controller.set('isWorking', true);
-      expect(App.updater.run.callCount).to.equal(13);
+      expect(App.updater.run.callCount).to.equal(14);
     });
   });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/test/controllers/main/assemblies/assemblies_set_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/assemblies/assemblies_set_controller_test.js b/ambari-web/test/controllers/main/assemblies/assemblies_set_controller_test.js
new file mode 100644
index 0000000..10c2234
--- /dev/null
+++ b/ambari-web/test/controllers/main/assemblies/assemblies_set_controller_test.js
@@ -0,0 +1,35 @@
+/**
+ * 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 = require('app');
+
+function getController() {
+  return App.MainAssembliesSetController.create();
+}
+
+describe('App.MainAssembliesSetController', function() {
+
+  App.TestAliases.testAsComputedEqual(getController(), 'storeAppsEmpty', 'content.storeApps.length', 0);
+
+  App.TestAliases.testAsComputedFindBy(getController(), 'activeStoreApp', 'content.storeApps', 'isActive', true);
+
+  App.TestAliases.testAsComputedFilterBy(getController(), 'components', 'filteredStoreApps', 'isComponent', true);
+
+  App.TestAliases.testAsComputedFilterBy(getController(), 'assemblies', 'filteredStoreApps', 'isComponent', false);
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/test/controllers/main/assemblies_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/assemblies_controller_test.js b/ambari-web/test/controllers/main/assemblies_controller_test.js
new file mode 100644
index 0000000..09d2543
--- /dev/null
+++ b/ambari-web/test/controllers/main/assemblies_controller_test.js
@@ -0,0 +1,35 @@
+/**
+ * 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 = require('app');
+
+function getController() {
+  return App.MainAssembliesController.create();
+}
+
+describe('App.MainAssembliesController', function() {
+
+  App.TestAliases.testAsComputedFindBy(getController(), 'activeStoreCollection', 'storeCollections', 'isActive', true);
+
+  App.TestAliases.testAsComputedEveryBy(getController(), 'noCategorySelected', 'storeCategories', 'isActive', false);
+
+  App.TestAliases.testAsComputedEveryBy(getController(), 'noCollectionSelected', 'storeCollections', 'isActive', false);
+
+  App.TestAliases.testAsComputedAnd(getController(), 'allAppsAreShown', ['noCategorySelected', 'noCollectionSelected']);
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/test/controllers/main/service_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service_test.js b/ambari-web/test/controllers/main/service_test.js
index 9db4849..8e1e952 100644
--- a/ambari-web/test/controllers/main/service_test.js
+++ b/ambari-web/test/controllers/main/service_test.js
@@ -87,67 +87,6 @@ describe('App.MainServiceController', function () {
     mainServiceController.destroy();
   });
 
-  App.TestAliases.testAsComputedNotEqual(getController(), 'isStartStopAllClicked', 'App.router.backgroundOperationsController.allOperationsCount', 0);
-
-  describe('#isStartAllDisabled', function () {
-    tests.forEach(function (test) {
-      it(test.mStart, function () {
-        mainServiceController = App.MainServiceController.create({
-          content: test.content,
-          isStartStopAllClicked: test.isStartStopAllClicked
-        });
-        expect(mainServiceController.get('isStartAllDisabled')).to.equals(test.eStart);
-      });
-    });
-  });
-
-  describe('#isStopAllDisabled', function () {
-    tests.forEach(function (test) {
-      it(test.mStop, function () {
-        mainServiceController = App.MainServiceController.create({
-          content: test.content,
-          isStartStopAllClicked: test.isStartStopAllClicked
-        });
-        expect(mainServiceController.get('isStopAllDisabled')).to.equals(test.eStop);
-      });
-    });
-  });
-
-  describe("#isAllServicesInstalled", function() {
-
-    beforeEach(function() {
-      sinon.stub(App.StackService, 'find').returns([
-        Em.Object.create({serviceName: 'S1'})
-      ]);
-    });
-    afterEach(function() {
-      App.StackService.find.restore();
-    });
-
-    it("content is null", function() {
-      mainServiceController.reopen({
-        'content': null
-      });
-      mainServiceController.propertyDidChange('isAllServicesInstalled');
-      expect(mainServiceController.get('isAllServicesInstalled')).to.be.false;
-    });
-
-    it("content is empty", function() {
-      mainServiceController.reopen({
-        'content': []
-      });
-      mainServiceController.propertyDidChange('isAllServicesInstalled');
-      expect(mainServiceController.get('isAllServicesInstalled')).to.be.false;
-    });
-
-    it("content match stack services", function() {
-      mainServiceController.reopen({
-        'content': [Em.Object.create({serviceName: 'S1'})]
-      });
-      mainServiceController.propertyDidChange('isAllServicesInstalled');
-      expect(mainServiceController.get('isAllServicesInstalled')).to.be.true;
-    });
-  });
 
   describe('#cluster', function() {
 
@@ -192,56 +131,10 @@ describe('App.MainServiceController', function () {
 
   });
 
-  describe('#startAllService', function() {
-
-    beforeEach(function() {
-      sinon.stub(mainServiceController, 'allServicesCall', Em.K);
-    });
-
-    afterEach(function() {
-      mainServiceController.allServicesCall.restore();
-    });
-
-    it('target is disabled', function() {
-      var event = {target: {className: 'disabled', nodeType: 1}};
-      var r = mainServiceController.startAllService(event);
-      expect(r).to.be.null;
-    });
-
-    it('parent is disabled', function() {
-      var event = {target: {parentElement: {className: 'disabled', nodeType: 1}}};
-      var r = mainServiceController.startAllService(event);
-      expect(r).to.be.null;
-    });
-
-  });
-
-  describe('#stopAllService', function() {
-
-    beforeEach(function() {
-      sinon.stub(mainServiceController, 'allServicesCall', Em.K);
-    });
-
-    afterEach(function() {
-      mainServiceController.allServicesCall.restore();
-    });
-
-    it('target is disabled', function() {
-      var event = {target: {className: 'disabled', nodeType: 1}};
-      var r = mainServiceController.stopAllService(event);
-      expect(r).to.be.null;
-    });
-
-    it('parent is disabled', function() {
-      var event = {target: {parentElement: {className: 'disabled', nodeType: 1}}};
-      var r = mainServiceController.stopAllService(event);
-      expect(r).to.be.null;
-    });
-
-  });
-
   describe('#startStopAllService', function() {
-    var event = { target: document.createElement("BUTTON") };
+    var serviceGroup = Em.Object.create({
+      serviceGroupName: 'CORE'
+    });
 
     beforeEach(function() {
       sinon.stub(mainServiceController, 'allServicesCall', Em.K);
@@ -254,8 +147,8 @@ describe('App.MainServiceController', function () {
     });
 
     it ("should confirm stop if state is INSTALLED", function() {
-      mainServiceController.startStopAllService(event, "INSTALLED");
-      expect(Em.I18n.t.calledWith('services.service.stopAll.confirmMsg')).to.be.ok;
+      mainServiceController.startStopAllService(serviceGroup, "INSTALLED");
+      expect(Em.I18n.t.calledWith('services.service.core.stopAll.confirmMsg')).to.be.ok;
       expect(Em.I18n.t.calledWith('services.service.stop.confirmButton')).to.be.ok;
     });
 
@@ -287,15 +180,15 @@ describe('App.MainServiceController', function () {
       });
 
       it('checkNnLastCheckpointTime is called once', function () {
-        mainServiceController.startStopAllService(event, "INSTALLED");
+        mainServiceController.startStopAllService(serviceGroup, "INSTALLED");
         expect(mainServiceItemController.checkNnLastCheckpointTime.calledOnce).to.equal(true);
       });
 
     });
 
     it ("should confirm start if state is not INSTALLED", function() {
-      mainServiceController.startStopAllService(event, "STARTED");
-      expect(Em.I18n.t.calledWith('services.service.startAll.confirmMsg')).to.be.ok;
+      mainServiceController.startStopAllService(serviceGroup, "STARTED");
+      expect(Em.I18n.t.calledWith('services.service.core.startAll.confirmMsg')).to.be.ok;
       expect(Em.I18n.t.calledWith('services.service.start.confirmButton')).to.be.ok;
     });
   });
@@ -304,13 +197,26 @@ describe('App.MainServiceController', function () {
 
     var state = 'STARTED',
       query = 'some query';
+    var serviceGroup = Em.Object.create({
+      services: [
+        Em.Object.create({
+          serviceName: 'HDFS'
+        }),
+        Em.Object.create({
+          serviceName: 'YARN'
+        }),
+        Em.Object.create({
+          serviceName: 'MAPREDUCE2'
+        })
+      ]
+    });
 
     beforeEach(function() {
       sinon.stub(App, 'get', function(k) {
         if ('clusterName' === k) return 'tdk';
         return Em.get(App, k);
       });
-      mainServiceController.allServicesCall(state, query);
+      mainServiceController.allServicesCall(state, query, serviceGroup);
       var args = testHelpers.findAjaxRequest('name', 'common.services.update');
       this.params = App.ajax.fakeGetUrl('common.services.update').format(args[0].data);
       this.data = JSON.parse(this.params.data);
@@ -353,21 +259,19 @@ describe('App.MainServiceController', function () {
     });
 
     it('should not go to wizard', function() {
-      mainServiceController.reopen({isAllServicesInstalled: true});
+      mainServiceController.reopen({isAllCoreServicesInstalled: true});
       mainServiceController.gotoAddService();
       expect(App.router.transitionTo.called).to.be.false;
     });
 
     it('should go to wizard', function() {
-      mainServiceController.reopen({isAllServicesInstalled: false});
+      mainServiceController.reopen({isAllCoreServicesInstalled: false});
       mainServiceController.gotoAddService();
       expect(App.router.transitionTo.calledWith('main.serviceAdd')).to.be.true;
     });
 
   });
 
-  App.TestAliases.testAsComputedEveryBy(getController(), 'isRestartAllRequiredDisabled', 'content', 'isRestartRequired', false);
-
   describe('#restartAllRequired', function () {
 
     beforeEach(function () {
@@ -411,23 +315,20 @@ describe('App.MainServiceController', function () {
       App.showConfirmationPopup.restore();
       mainServiceController.restartHostComponents.restore();
     });
+    var serviceGroup = Em.Object.create({
+      isRestartAllRequiredDisabled: false
+    });
 
     it('should show confirmation popup with list of services and call restartHostComponents after confirmation', function () {
-      var popup;
-      mainServiceController.reopen({
-        isRestartAllRequiredDisabled: false
-      });
-      popup = mainServiceController.restartAllRequired();
+      var popup = mainServiceController.restartAllRequired(serviceGroup);
       popup.onPrimary();
       expect(App.showConfirmationPopup.args[0][1]).to.equal(Em.I18n.t('services.service.refreshAll.confirmMsg').format('displayName1, displayName2'));
       expect(mainServiceController.restartHostComponents.calledOnce).to.be.true;
     });
 
     it('should not open popup if isRestartAllRequiredDisabled is true', function(){
-      mainServiceController.reopen({
-        isRestartAllRequiredDisabled: true
-      });
-      expect(mainServiceController.restartAllRequired()).to.be.null;
+      serviceGroup.set('isRestartAllRequiredDisabled', true);
+      expect(mainServiceController.restartAllRequired(serviceGroup)).to.be.null;
     });
 
   });

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/test/models/service_group_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/service_group_test.js b/ambari-web/test/models/service_group_test.js
new file mode 100644
index 0000000..ff91682
--- /dev/null
+++ b/ambari-web/test/models/service_group_test.js
@@ -0,0 +1,47 @@
+/**
+ * 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 = require('app');
+
+function getModel() {
+  return App.ServiceGroup.createRecord();
+}
+
+describe('App.ServiceGroup', function () {
+
+  App.TestAliases.testAsComputedOr(getModel(), 'isStartAllDisabled', ['isStartStopAllClicked', '!someServiceIsStopped']);
+
+  App.TestAliases.testAsComputedOr(getModel(), 'isStopAllDisabled', ['isStartStopAllClicked', '!someServiceIsStarted']);
+
+  App.TestAliases.testAsComputedEveryBy(getModel(), 'isRestartAllRequiredDisabled', 'services', 'isRestartRequired', false);
+
+  App.TestAliases.testAsComputedSomeBy(getModel(), 'someServiceIsStarted', 'services', 'healthStatus', 'green');
+
+  App.TestAliases.testAsComputedEveryBy(getModel(), 'allServicesAreStarted', 'services', 'healthStatus', 'green');
+
+  App.TestAliases.testAsComputedNotEqual(getModel(), 'isStartStopAllClicked', 'App.router.backgroundOperationsController.allOperationsCount', 0);
+
+  App.TestAliases.testAsComputedEqual(getModel(), 'isCoreServiceGroup', 'serviceGroupName', 'CORE');
+
+  App.TestAliases.testAsComputedSumBy(getModel(), 'alertsCount', 'services', 'alertsCount');
+
+  App.TestAliases.testAsComputedEqual(getModel(), 'isStopped', 'desiredState', 'INSTALLED');
+
+  App.TestAliases.testAsComputedEqual(getModel(), 'isStarted', 'desiredState', 'STARTED');
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/test/views/main/assemblies/active_store_app_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/assemblies/active_store_app_view_test.js b/ambari-web/test/views/main/assemblies/active_store_app_view_test.js
new file mode 100644
index 0000000..0535bd5
--- /dev/null
+++ b/ambari-web/test/views/main/assemblies/active_store_app_view_test.js
@@ -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.
+ */
+
+var App = require('app');
+
+function getView() {
+  return App.ActiveStoreAppView.create({});
+}
+
+describe('App.ActiveStoreAppView', function() {
+
+  App.TestAliases.testAsComputedFirstNotBlank(getView(), 'title', ['storeApp.title', 'storeApp.name']);
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/test/views/main/assemblies/apps_row_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/assemblies/apps_row_view_test.js b/ambari-web/test/views/main/assemblies/apps_row_view_test.js
new file mode 100644
index 0000000..396c36b
--- /dev/null
+++ b/ambari-web/test/views/main/assemblies/apps_row_view_test.js
@@ -0,0 +1,39 @@
+/**
+ * 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 = require('app');
+
+var view;
+
+function getView() {
+  return App.AppsRowView.create({apps: []});
+}
+
+describe('App.AppsRowView', function() {
+
+  beforeEach(function() {
+    view = getView();
+  });
+
+  App.TestAliases.testAsComputedFindBy(getView(), 'activeApp', 'visibleApps', 'isActive', true);
+
+  App.TestAliases.testAsComputedEqual(getView(), 'disabledLeft', 'startIndex', 0);
+
+  App.TestAliases.testAsComputedGteProperties(getView(), 'disabledRight', 'endIndex', 'apps.length');
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/test/views/main/assemblies/store_app_block_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/assemblies/store_app_block_view_test.js b/ambari-web/test/views/main/assemblies/store_app_block_view_test.js
new file mode 100644
index 0000000..5794c92
--- /dev/null
+++ b/ambari-web/test/views/main/assemblies/store_app_block_view_test.js
@@ -0,0 +1,47 @@
+/**
+ * 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 = require('app');
+
+var view;
+
+function getView() {
+  return App.StoreAppBlockView.create({
+    storeApp: Em.Object.create({
+      storeCategories: [Em.Object.create({name: 'n1'}), Em.Object.create({name: 'n2'}), Em.Object.create({name: 'n3'})]
+    })
+  });
+}
+
+describe('App.StoreAppBlockView', function() {
+
+  beforeEach(function () {
+    view = getView();
+  });
+
+  describe('#categoryNames', function () {
+
+    it('should be mapped with coma', function () {
+      expect(view.get('categoryNames')).to.be.equal('n1, n2, n3');
+    });
+
+  });
+
+  App.TestAliases.testAsComputedGt(getView(), 'moreServices', 'storeApp.services.length', 19);
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/test/views/main/service/info/summary_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/service/info/summary_test.js b/ambari-web/test/views/main/service/info/summary_test.js
index d9fff97..a120ed0 100644
--- a/ambari-web/test/views/main/service/info/summary_test.js
+++ b/ambari-web/test/views/main/service/info/summary_test.js
@@ -559,11 +559,13 @@ describe('App.MainServiceInfoSummaryView', function() {
       sinon.stub(App.StackService, 'find').returns(mock);
       sinon.stub(view, 'getUserPref').returns({
         complete: function(callback){callback();}
-      })
+      });
+      view.set('controller.content.serviceGroupName', 'CORE');
     });
     afterEach(function() {
       App.StackService.find.restore();
       view.getUserPref.restore();
+      view.set('controller.content.serviceGroupName', undefined);
     });
 
     it("metrics not loaded", function() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/vendor/scripts/highlight.pack.js
----------------------------------------------------------------------
diff --git a/ambari-web/vendor/scripts/highlight.pack.js b/ambari-web/vendor/scripts/highlight.pack.js
new file mode 100644
index 0000000..ceb5ea6
--- /dev/null
+++ b/ambari-web/vendor/scripts/highlight.pack.js
@@ -0,0 +1,2 @@
+/*! highlight.js v9.4.0 | BSD3 License | git.io/hljslicense */
+!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0==t.index}function a(e){return/^(no-?highlight|plain|text)$/i.test(e)}function i(e){var n,t,r,i=e.className+" ";if(i+=e.parentNode?e.parentNode.className:"",t=/\blang(?:uage)?-([\w-]+)\b/i.exec(i))return w(t[1])?t[1]:"no-highlight";for(i=i.split(/\s+/),n=0,r=i.length;r>n;n++)if(w(i[n])||a(i[n]))return i[n]}function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3==i.nodeType?a+=i.nodeValue.length:1==i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match
 (/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!=r[0].offset?e[0].offset<r[0].offset?e:r:"start"==r[0].event?e:r:e.length?e:r}function o(e){function r(e){return" "+e.nodeName+'="'+n(e.value)+'"'}f+="<"+t(e)+Array.prototype.map.call(e.attributes,r).join("")+">"}function u(e){f+="</"+t(e)+">"}function c(e){("start"==e.event?o:u)(e.node)}for(var s=0,f="",l=[];e.length||r.length;){var g=i();if(f+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g==e){l.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g==e&&g.length&&g[0].offset==s);l.reverse().forEach(o)}else"start"==g[0].event?l.push(g[0].node):l.pop(),c(g.splice(0,1)[0])}return f+n(a.substr(s))}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(
 " ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):Object.keys(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),void 0===a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push("self"==e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var f=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=f.length?t(f.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e,n){for(var t=0;t<n.c.length;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e
 ,n){return!a&&r(n.iR,e)}function g(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function p(e,n,t,r){var a=r?"":E.classPrefix,i='<span class="'+a,o=t?"":"</span>";return i+=e+'">',i+n+o}function h(){if(!k.k)return n(M);var e="",t=0;k.lR.lastIndex=0;for(var r=k.lR.exec(M);r;){e+=n(M.substr(t,r.index-t));var a=g(k,r);a?(B+=a[1],e+=p(a[0],n(r[0]))):e+=n(r[0]),t=k.lR.lastIndex,r=k.lR.exec(M)}return e+n(M.substr(t))}function d(){var e="string"==typeof k.sL;if(e&&!R[k.sL])return n(M);var t=e?f(k.sL,M,!0,y[k.sL]):l(M,k.sL.length?k.sL:void 0);return k.r>0&&(B+=t.r),e&&(y[k.sL]=t.top),p(t.language,t.value,!1,!0)}function b(){L+=void 0!==k.sL?d():h(),M=""}function v(e,n){L+=e.cN?p(e.cN,"",!0):"",k=Object.create(e,{parent:{value:k}})}function m(e,n){if(M+=e,void 0===n)return b(),0;var t=o(n,k);if(t)return t.skip?M+=n:(t.eB&&(M+=n),b(),t.rB||t.eB||(M=n)),v(t,n),t.rB?0:n.length;var r=u(k,n);if(r){var a=k;a.skip?M+=n:(a.rE||a.eE||(M+=n),b(),a.eE&&(M=n));do k.cN&&(L+
 ="</span>"),k.skip||(B+=k.r),k=k.parent;while(k!=r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,k))throw new Error('Illegal lexeme "'+n+'" for mode "'+(k.cN||"<unnamed>")+'"');return M+=n,n.length||1}var N=w(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var x,k=i||N,y={},L="";for(x=k;x!=N;x=x.parent)x.cN&&(L=p(x.cN,"",!0)+L);var M="",B=0;try{for(var C,j,I=0;;){if(k.t.lastIndex=I,C=k.t.exec(t),!C)break;j=m(t.substr(I,C.index-I),C[0]),I=C.index+j}for(m(t.substr(I)),x=k;x.parent;x=x.parent)x.cN&&(L+="</span>");return{r:B,value:L,language:e,top:k}}catch(O){if(-1!=O.message.indexOf("Illegal"))return{r:0,value:n(t)};throw O}}function l(e,t){t=t||E.languages||Object.keys(R);var r={r:0,value:n(e)},a=r;return t.filter(w).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function g(e){return E.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,function(e,n){return n.replace(/\t/g,E.tabReplace)})),E.us
 eBR&&(e=e.replace(/\n/g,"<br>")),e}function p(e,n,t){var r=n?x[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function h(e){var n=i(e);if(!a(n)){var t;E.useBR?(t=document.createElementNS("http://www.w3.org/1999/xhtml","div"),t.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/<br[ \/]*>/g,"\n")):t=e;var r=t.textContent,o=n?f(n,r,!0):l(r),s=u(t);if(s.length){var h=document.createElementNS("http://www.w3.org/1999/xhtml","div");h.innerHTML=o.value,o.value=c(s,u(h),r)}o.value=g(o.value),e.innerHTML=o.value,e.className=p(e.className,n,o.language),e.result={language:o.language,re:o.r},o.second_best&&(e.second_best={language:o.second_best.language,re:o.second_best.r})}}function d(e){E=o(E,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("pre code");Array.prototype.forEach.call(e,h)}}function v(){addEventListener("DOMContentLoaded",b,!1),addEventListener("load",b,!1)}function m(n,t){var r=R[n]=t(e);r.alias
 es&&r.aliases.forEach(function(e){x[e]=n})}function N(){return Object.keys(R)}function w(e){return e=(e||"").toLowerCase(),R[e]||R[x[e]]}var E={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},R={},x={};return e.highlight=f,e.highlightAuto=l,e.fixMarkup=g,e.highlightBlock=h,e.configure=d,e.initHighlighting=b,e.initHighlightingOnLoad=v,e.registerLanguage=m,e.listLanguages=N,e.getLanguage=w,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\
 b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("json",function(e){var i={literal:"true false null"},n=[e.QSM,e.CNM],r={e:",",eW:!0,eE:!0,c:n,k:i},t={b:"{",e:"}",c:[{cN:"attr",b:/"/,e:/"/,c:[e.BE],i:"\\n"},e.inherit(r,{b:/:/})],i:"\\S"},c={b:"\\[",e:"\\]",c:[e.inherit(r)],i:"\\S"};return n.splice(n.length,0,t,c),{c:n,k:i,i:"\\S"}});hljs.registerLanguage("xml",function(s){var e="
 [A-Za-z0-9\\._:-]+",t={eW:!0,i:/</,r:0,c:[{cN:"attr",b:e,r:0},{b:/=\s*/,r:0,c:[{cN:"string",endsParent:!0,v:[{b:/"/,e:/"/},{b:/'/,e:/'/},{b:/[^\s"'=<>`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"<!DOCTYPE",e:">",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("<!--","-->",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0}]},{cN:"tag",b:"<style(?=\\s|>|$)",e:">",k:{name:"style"},c:[t],starts:{e:"</style>",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"<script(?=\\s|>|$)",e:">",k:{name:"script"},c:[t],starts:{e:"</script>",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"meta",v:[{b:/<\?xml/,e:/\?>/,r:10},{b:/<\?\w+/,e:/\?>/}]},{cN:"tag",b:"</?",e:"/?>",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("javascript",function(e){return{aliases:["js","jsx"],k:{keyword:"in of if for while finally var new function do return void else break catch instanceof with throw
  case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"}]},e.CLCM,e.CBCM,{cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},{b:"("+e.RSR+"|\\b(case|return|throw)\
 \b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/</,e:/(\/\w+|\w+\/)>/,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:["self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:[e.CLCM,e.CBCM]}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-web/vendor/styles/highlight.css
----------------------------------------------------------------------
diff --git a/ambari-web/vendor/styles/highlight.css b/ambari-web/vendor/styles/highlight.css
new file mode 100644
index 0000000..f1bfade
--- /dev/null
+++ b/ambari-web/vendor/styles/highlight.css
@@ -0,0 +1,99 @@
+/*
+
+Original highlight.js style (c) Ivan Sagalaev <ma...@softwaremaniacs.org>
+
+*/
+
+.hljs {
+  display: block;
+  overflow-x: auto;
+  padding: 0.5em;
+  background: #F0F0F0;
+}
+
+
+/* Base color: saturation 0; */
+
+.hljs,
+.hljs-subst {
+  color: #444;
+}
+
+.hljs-comment {
+  color: #888888;
+}
+
+.hljs-keyword,
+.hljs-attribute,
+.hljs-selector-tag,
+.hljs-meta-keyword,
+.hljs-doctag,
+.hljs-name {
+  font-weight: bold;
+}
+
+
+/* User color: hue: 0 */
+
+.hljs-type,
+.hljs-string,
+.hljs-number,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-quote,
+.hljs-template-tag,
+.hljs-deletion {
+  color: #880000;
+}
+
+.hljs-title,
+.hljs-section {
+  color: #880000;
+  font-weight: bold;
+}
+
+.hljs-regexp,
+.hljs-symbol,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-link,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #BC6060;
+}
+
+
+/* Language color: hue: 90; */
+
+.hljs-literal {
+  color: #78A960;
+}
+
+.hljs-built_in,
+.hljs-bullet,
+.hljs-code,
+.hljs-addition {
+  color: #397300;
+}
+
+
+/* Meta color: hue: 200 */
+
+.hljs-meta {
+  color: #1f7199;
+}
+
+.hljs-meta-string {
+  color: #4d99bf;
+}
+
+
+/* Misc effects */
+
+.hljs-emphasis {
+  font-style: italic;
+}
+
+.hljs-strong {
+  font-weight: bold;
+}


[25/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommandTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommandTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommandTest.java
index bc9cf77..4ce096c 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommandTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/ConfigurationRecommendationCommandTest.java
@@ -34,6 +34,7 @@ import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
 import org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.junit.Test;
 
 public class ConfigurationRecommendationCommandTest {
@@ -43,7 +44,7 @@ public class ConfigurationRecommendationCommandTest {
     StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
     File file = mock(File.class);
     AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
-    ConfigurationRecommendationCommand command = new ConfigurationRecommendationCommand(file, "script", 1, saRunner, metaInfo);
+    ConfigurationRecommendationCommand command = new ConfigurationRecommendationCommand(ApiVersion.v1, file, "script", 1, saRunner, metaInfo);
 
     StackAdvisorRequest request = mock(StackAdvisorRequest.class);
     Map<String, Set<String>> componentHostGroupMap = new HashMap<String, Set<String>>();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java
index 263bbe1..011bbc7 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java
@@ -47,6 +47,7 @@ import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequestExc
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorResponse;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
 import org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommand.StackAdvisorData;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.commons.io.FileUtils;
 import org.codehaus.jackson.JsonNode;
 import org.codehaus.jackson.annotate.JsonProperty;
@@ -261,7 +262,7 @@ public class StackAdvisorCommandTest {
   class TestStackAdvisorCommand extends StackAdvisorCommand<TestResource> {
     public TestStackAdvisorCommand(File recommendationsDir, String stackAdvisorScript,
         int requestId, StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
-      super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
+      super(ApiVersion.v1, recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/audit/request/creator/ServiceEventCreatorTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/audit/request/creator/ServiceEventCreatorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/audit/request/creator/ServiceEventCreatorTest.java
index 01cc1e3..607a9cd 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/audit/request/creator/ServiceEventCreatorTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/audit/request/creator/ServiceEventCreatorTest.java
@@ -104,6 +104,7 @@ public class ServiceEventCreatorTest extends AuditEventCreatorTestBase {
     Map<String,Object> properties = new HashMap<>();
     properties.put(ServiceResourceProvider.SERVICE_SERVICE_STATE_PROPERTY_ID, "STARTED");
     properties.put(ServiceResourceProvider.SERVICE_SERVICE_NAME_PROPERTY_ID, "MyService");
+    properties.put(ServiceResourceProvider.SERVICE_STACK_SERVICE_NAME_PROPERTY_ID, "MyService");
 
     Request request = AuditEventCreatorTestHelper.createRequest(Request.Type.PUT, Resource.Type.Service, properties, null);
     request.getBody().addRequestInfoProperty(RequestOperationLevel.OPERATION_LEVEL_ID, "SERVICE");
@@ -131,6 +132,7 @@ public class ServiceEventCreatorTest extends AuditEventCreatorTestBase {
     Map<String,Object> properties = new HashMap<>();
     properties.put(ServiceResourceProvider.SERVICE_MAINTENANCE_STATE_PROPERTY_ID, "ON");
     properties.put(ServiceResourceProvider.SERVICE_SERVICE_NAME_PROPERTY_ID, "MyService");
+    properties.put(ServiceResourceProvider.SERVICE_STACK_SERVICE_NAME_PROPERTY_ID, "MyService");
 
     Request request = AuditEventCreatorTestHelper.createRequest(Request.Type.PUT, Resource.Type.Service, properties, null);
 
@@ -156,6 +158,7 @@ public class ServiceEventCreatorTest extends AuditEventCreatorTestBase {
     Map<String,Object> properties = new HashMap<>();
     properties.put(ServiceResourceProvider.SERVICE_MAINTENANCE_STATE_PROPERTY_ID, "ON");
     properties.put(ServiceResourceProvider.SERVICE_SERVICE_NAME_PROPERTY_ID, "MyService");
+    properties.put(ServiceResourceProvider.SERVICE_STACK_SERVICE_NAME_PROPERTY_ID, "MyService");
 
     Request request = AuditEventCreatorTestHelper.createRequest(Request.Type.PUT, Resource.Type.Service, properties, null);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/configuration/RecoveryConfigHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/configuration/RecoveryConfigHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/configuration/RecoveryConfigHelperTest.java
index 93d261b..2d6a5be 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/configuration/RecoveryConfigHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/configuration/RecoveryConfigHelperTest.java
@@ -132,7 +132,7 @@ public class RecoveryConfigHelperTest {
   public void testServiceComponentInstalled()
       throws AmbariException {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
 
     hdfs.addServiceComponent(DATANODE).setRecoveryEnabled(true);
@@ -168,7 +168,7 @@ public class RecoveryConfigHelperTest {
   public void testServiceComponentUninstalled()
       throws AmbariException {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
 
     hdfs.addServiceComponent(DATANODE).setRecoveryEnabled(true);
@@ -206,7 +206,7 @@ public class RecoveryConfigHelperTest {
   public void testClusterEnvConfigChanged()
       throws AmbariException {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
 
     hdfs.addServiceComponent(DATANODE).setRecoveryEnabled(true);
@@ -246,7 +246,7 @@ public class RecoveryConfigHelperTest {
   public void testMaintenanceModeChanged()
       throws AmbariException {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
 
     hdfs.addServiceComponent(DATANODE).setRecoveryEnabled(true);
@@ -283,7 +283,7 @@ public class RecoveryConfigHelperTest {
   public void testServiceComponentRecoveryChanged()
       throws AmbariException {
     Cluster cluster = heartbeatTestHelper.getDummyCluster();
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
 
     hdfs.addServiceComponent(DATANODE).setRecoveryEnabled(true);
@@ -326,7 +326,7 @@ public class RecoveryConfigHelperTest {
     Cluster cluster = getDummyCluster(hostNames);
 
     // Add HDFS service with DATANODE component to the cluster
-    Service hdfs = cluster.addService(HDFS);
+    Service hdfs = cluster.addService(HDFS, HDFS, "CORE");
     hdfs.persist();
 
     hdfs.addServiceComponent(DATANODE).setRecoveryEnabled(true);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
index 1ecadc4..f0fe44d 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
@@ -453,7 +453,7 @@ public class AmbariCustomCommandExecutionHelperTest {
     if (desiredState != null) {
       dStateStr = desiredState.toString();
     }
-    ServiceRequest r1 = new ServiceRequest(clusterName, serviceName, dStateStr);
+    ServiceRequest r1 = new ServiceRequest(clusterName, serviceName, serviceName, "CORE", dStateStr);
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r1);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
index 1a7ff67..1015064 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
@@ -372,7 +372,7 @@ public class AmbariManagementControllerImplTest {
 
     expect(service.getName()).andReturn("service");
     expect(service.getServiceComponent("component")).andThrow(
-      new ServiceComponentNotFoundException("cluster", "service", "component"));
+      new ServiceComponentNotFoundException("cluster", "service", "service", "CORE", "component"));
     expect(service.getDesiredStackVersion()).andReturn(stackId);
     expect(stackId.getStackName()).andReturn("stack");
     expect(stackId.getStackVersion()).andReturn("1.0");
@@ -1504,7 +1504,7 @@ public class AmbariManagementControllerImplTest {
     expect(ambariMetaInfo.getComponentToService("stackName", "stackVersion", "component2")).andReturn("service2");
     expect(cluster.getService("service2")).andReturn(service2);
     expect(service2.getServiceComponent("component2")).
-        andThrow(new ServiceComponentNotFoundException("cluster1", "service2", "component2"));
+        andThrow(new ServiceComponentNotFoundException("cluster1", "service2", "service2", "CORE", "component2"));
 
     expect(ambariMetaInfo.getComponentToService("stackName", "stackVersion", "component3")).andReturn("service1");
     expect(cluster.getService("service1")).andReturn(service);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index 3ec9cb3..570cc7d 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@ -335,7 +335,7 @@ public class AmbariManagementControllerTest {
     if (desiredState != null) {
       dStateStr = desiredState.toString();
     }
-    ServiceRequest r1 = new ServiceRequest(clusterName, serviceName, dStateStr);
+    ServiceRequest r1 = new ServiceRequest(clusterName, serviceName, serviceName, "CORE", dStateStr);
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r1);
 
@@ -416,7 +416,7 @@ public class AmbariManagementControllerTest {
   private long stopService(String clusterName, String serviceName,
       boolean runSmokeTests, boolean reconfigureClients) throws
       AmbariException, AuthorizationException {
-    ServiceRequest r = new ServiceRequest(clusterName, serviceName, State.INSTALLED.toString());
+    ServiceRequest r = new ServiceRequest(clusterName, serviceName, serviceName, "CORE", State.INSTALLED.toString());
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r);
     Map<String, String> mapRequestProps = new HashMap<String, String>();
@@ -481,7 +481,7 @@ public class AmbariManagementControllerTest {
                             boolean runSmokeTests, boolean reconfigureClients,
                             MaintenanceStateHelper maintenanceStateHelper) throws
       AmbariException, AuthorizationException {
-    ServiceRequest r = new ServiceRequest(clusterName, serviceName,
+    ServiceRequest r = new ServiceRequest(clusterName, serviceName, serviceName, "CORE",
         State.STARTED.toString());
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r);
@@ -536,7 +536,7 @@ public class AmbariManagementControllerTest {
                               Map<String, String> mapRequestPropsInput)
       throws AmbariException, AuthorizationException {
 
-    ServiceRequest r = new ServiceRequest(clusterName, serviceName,
+    ServiceRequest r = new ServiceRequest(clusterName, serviceName, serviceName, "CORE",
         State.INSTALLED.toString());
 
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
@@ -690,7 +690,7 @@ public class AmbariManagementControllerTest {
     Assert.assertEquals(serviceName, s.getName());
     Assert.assertEquals(cluster1, s.getCluster().getClusterName());
 
-    ServiceRequest req = new ServiceRequest(cluster1, serviceName, null);
+    ServiceRequest req = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", null);
 
     Set<ServiceResponse> r =
         ServiceResourceProviderTest.getServices(controller, Collections.singleton(req));
@@ -715,7 +715,7 @@ public class AmbariManagementControllerTest {
 
     try {
       set1.clear();
-      ServiceRequest rInvalid = new ServiceRequest(null, null, null);
+      ServiceRequest rInvalid = new ServiceRequest(null, null, null, "CORE", null);
       set1.add(rInvalid);
       ServiceResourceProviderTest.createServices(controller, set1);
       fail("Expected failure for invalid requests");
@@ -725,7 +725,7 @@ public class AmbariManagementControllerTest {
 
     try {
       set1.clear();
-      ServiceRequest rInvalid = new ServiceRequest("foo", null, null);
+      ServiceRequest rInvalid = new ServiceRequest("foo", null, null, "CORE",  null);
       set1.add(rInvalid);
       ServiceResourceProviderTest.createServices(controller, set1);
       fail("Expected failure for invalid requests");
@@ -735,7 +735,7 @@ public class AmbariManagementControllerTest {
 
     try {
       set1.clear();
-      ServiceRequest rInvalid = new ServiceRequest("foo", "bar", null);
+      ServiceRequest rInvalid = new ServiceRequest("foo", "bar", "bar", "CORE", null);
       set1.add(rInvalid);
       ServiceResourceProviderTest.createServices(controller, set1);
       fail("Expected failure for invalid cluster");
@@ -753,8 +753,8 @@ public class AmbariManagementControllerTest {
 
     try {
       set1.clear();
-      ServiceRequest valid1 = new ServiceRequest(cluster1, "HDFS", null);
-      ServiceRequest valid2 = new ServiceRequest(cluster1, "HDFS", null);
+      ServiceRequest valid1 = new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null);
+      ServiceRequest valid2 = new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null);
       set1.add(valid1);
       set1.add(valid2);
       ServiceResourceProviderTest.createServices(controller, set1);
@@ -765,7 +765,7 @@ public class AmbariManagementControllerTest {
 
     try {
       set1.clear();
-      ServiceRequest valid1 = new ServiceRequest(cluster1, "bar", null);
+      ServiceRequest valid1 = new ServiceRequest(cluster1, "bar", "bar", "CORE", null);
       set1.add(valid1);
       ServiceResourceProviderTest.createServices(controller, set1);
       fail("Expected failure for invalid service");
@@ -776,8 +776,8 @@ public class AmbariManagementControllerTest {
 
     try {
       set1.clear();
-      ServiceRequest valid1 = new ServiceRequest(cluster1, "HDFS", null);
-      ServiceRequest valid2 = new ServiceRequest(cluster2, "HDFS", null);
+      ServiceRequest valid1 = new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null);
+      ServiceRequest valid2 = new ServiceRequest(cluster2, "HDFS", "HDFS", "CORE", null);
       set1.add(valid1);
       set1.add(valid2);
       ServiceResourceProviderTest.createServices(controller, set1);
@@ -790,14 +790,14 @@ public class AmbariManagementControllerTest {
     Assert.assertEquals(0, clusters.getCluster(cluster1).getServices().size());
 
     set1.clear();
-    ServiceRequest valid = new ServiceRequest(cluster1, "HDFS", null);
+    ServiceRequest valid = new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null);
     set1.add(valid);
     ServiceResourceProviderTest.createServices(controller, set1);
 
     try {
       set1.clear();
-      ServiceRequest valid1 = new ServiceRequest(cluster1, "HDFS", null);
-      ServiceRequest valid2 = new ServiceRequest(cluster1, "HDFS", null);
+      ServiceRequest valid1 = new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null);
+      ServiceRequest valid2 = new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null);
       set1.add(valid1);
       set1.add(valid2);
       ServiceResourceProviderTest.createServices(controller, set1);
@@ -839,7 +839,7 @@ public class AmbariManagementControllerTest {
     String serviceName2 = "MAPREDUCE";
     createService(cluster1, serviceName2, State.INIT);
 
-    ServiceRequest r = new ServiceRequest(cluster1, null, null);
+    ServiceRequest r = new ServiceRequest(cluster1, null, null, "CORE", null);
     Set<ServiceResponse> response = ServiceResourceProviderTest.getServices(controller, Collections.singleton(r));
     Assert.assertEquals(2, response.size());
 
@@ -859,15 +859,15 @@ public class AmbariManagementControllerTest {
 
     clusters.addCluster(cluster1, new StackId("HDP-0.1"));
 
-    ServiceRequest valid1 = new ServiceRequest(cluster1, "HDFS", null);
-    ServiceRequest valid2 = new ServiceRequest(cluster1, "MAPREDUCE", null);
+    ServiceRequest valid1 = new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null);
+    ServiceRequest valid2 = new ServiceRequest(cluster1, "MAPREDUCE", "MAPREDUCE", "CORE", null);
     set1.add(valid1);
     set1.add(valid2);
     ServiceResourceProviderTest.createServices(controller, set1);
 
     try {
-      valid1 = new ServiceRequest(cluster1, "PIG", null);
-      valid2 = new ServiceRequest(cluster1, "MAPREDUCE", null);
+      valid1 = new ServiceRequest(cluster1, "PIG", "PIG", "CORE", null);
+      valid2 = new ServiceRequest(cluster1, "MAPREDUCE", "MAPREDUCE", "CORE", null);
       set1.add(valid1);
       set1.add(valid2);
       ServiceResourceProviderTest.createServices(controller, set1);
@@ -1001,8 +1001,8 @@ public class AmbariManagementControllerTest {
     helper.getOrCreateRepositoryVersion(stackId, stackId.getStackVersion());
     c1.createClusterVersion(stackId, stackId.getStackVersion(), "admin",
         RepositoryVersionState.INSTALLING);
-    Service s1 = serviceFactory.createNew(c1, "HDFS");
-    Service s2 = serviceFactory.createNew(c1, "MAPREDUCE");
+    Service s1 = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
+    Service s2 = serviceFactory.createNew(c1, "MAPREDUCE", "MAPREDUCE", "CORE");
     c1.addService(s1);
     c1.addService(s2);
     s1.persist();
@@ -1306,8 +1306,8 @@ public class AmbariManagementControllerTest {
     c1.createClusterVersion(stackId, stackId.getStackVersion(), "admin",
         RepositoryVersionState.INSTALLING);
 
-    Service s1 = serviceFactory.createNew(c1, "HDFS");
-    Service s2 = serviceFactory.createNew(c1, "MAPREDUCE");
+    Service s1 = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
+    Service s2 = serviceFactory.createNew(c1, "MAPREDUCE", "MAPREDUCE", "CORE");
     c1.addService(s1);
     c1.addService(s2);
     s1.persist();
@@ -1619,13 +1619,13 @@ public class AmbariManagementControllerTest {
       // Expected
     }
 
-    Service s1 = serviceFactory.createNew(foo, "HDFS");
+    Service s1 = serviceFactory.createNew(foo, "HDFS", "HDFS", "CORE");
     foo.addService(s1);
     s1.persist();
-    Service s2 = serviceFactory.createNew(c1, "HDFS");
+    Service s2 = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
     c1.addService(s2);
     s2.persist();
-    Service s3 = serviceFactory.createNew(c2, "HDFS");
+    Service s3 = serviceFactory.createNew(c2, "HDFS", "HDFS", "CORE");
     c2.addService(s3);
     s3.persist();
 
@@ -1956,7 +1956,7 @@ public class AmbariManagementControllerTest {
     c1.persist();
     configs.put(c1.getType(), c1);
 
-    ServiceRequest r = new ServiceRequest(cluster1, serviceName, State.INSTALLED.toString());
+    ServiceRequest r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", State.INSTALLED.toString());
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r);
 
@@ -2016,7 +2016,7 @@ public class AmbariManagementControllerTest {
     configs.put(c1.getType(), c1);
     configs.put(c2.getType(), c2);
 
-    ServiceRequest r = new ServiceRequest(cluster1, serviceName, State.INSTALLED.toString());
+    ServiceRequest r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", State.INSTALLED.toString());
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r);
 
@@ -2124,7 +2124,7 @@ public class AmbariManagementControllerTest {
       }
     }
 
-    r = new ServiceRequest(cluster1, serviceName, State.STARTED.toString());
+    r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", State.STARTED.toString());
     requests.clear();
     requests.add(r);
     trackAction = ServiceResourceProviderTest.updateServices(controller, requests, mapRequestProps, true,
@@ -2170,7 +2170,7 @@ public class AmbariManagementControllerTest {
       }
     }
 
-    r = new ServiceRequest(cluster1, serviceName, State.INSTALLED.toString());
+    r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", State.INSTALLED.toString());
     requests.clear();
     requests.add(r);
     trackAction = ServiceResourceProviderTest.updateServices(controller, requests, mapRequestProps, true,
@@ -2269,7 +2269,7 @@ public class AmbariManagementControllerTest {
 
     clusters.addCluster(cluster1, new StackId("HDP-0.1"));
     Cluster c1 = clusters.getCluster(cluster1);
-    Service s1 = serviceFactory.createNew(c1, "HDFS");
+    Service s1 = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
 
     c1.addService(s1);
     s1.setDesiredStackVersion(new StackId("HDP-0.1"));
@@ -2277,7 +2277,7 @@ public class AmbariManagementControllerTest {
 
     s1.persist();
 
-    ServiceRequest r = new ServiceRequest(cluster1, null, null);
+    ServiceRequest r = new ServiceRequest(cluster1, null, null, "CORE", null);
     Set<ServiceResponse> resp = ServiceResourceProviderTest.getServices(controller, Collections.singleton(r));
 
     ServiceResponse resp1 = resp.iterator().next();
@@ -2305,11 +2305,11 @@ public class AmbariManagementControllerTest {
     c1.setDesiredStackVersion(new StackId("HDP-0.2"));
     c2.setDesiredStackVersion(new StackId("HDP-0.2"));
 
-    Service s1 = serviceFactory.createNew(c1, "HDFS");
-    Service s2 = serviceFactory.createNew(c1, "MAPREDUCE");
-    Service s3 = serviceFactory.createNew(c1, "HBASE");
-    Service s4 = serviceFactory.createNew(c2, "HIVE");
-    Service s5 = serviceFactory.createNew(c2, "ZOOKEEPER");
+    Service s1 = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
+    Service s2 = serviceFactory.createNew(c1, "MAPREDUCE", "MAPREDUCE", "CORE");
+    Service s3 = serviceFactory.createNew(c1, "HBASE", "HBASE", "CORE");
+    Service s4 = serviceFactory.createNew(c2, "HIVE", "HIVE", "CORE");
+    Service s5 = serviceFactory.createNew(c2, "ZOOKEEPER", "ZOOKEEPER", "CORE");
 
     c1.addService(s1);
     c1.addService(s2);
@@ -2327,7 +2327,7 @@ public class AmbariManagementControllerTest {
     s4.persist();
     s5.persist();
 
-    ServiceRequest r = new ServiceRequest(null, null, null);
+    ServiceRequest r = new ServiceRequest(null, null, null, "CORE", null);
     Set<ServiceResponse> resp;
 
     try {
@@ -2337,35 +2337,35 @@ public class AmbariManagementControllerTest {
       // Expected
     }
 
-    r = new ServiceRequest(c1.getClusterName(), null, null);
+    r = new ServiceRequest(c1.getClusterName(), null, null, "CORE", null);
     resp = ServiceResourceProviderTest.getServices(controller, Collections.singleton(r));
     Assert.assertEquals(3, resp.size());
 
-    r = new ServiceRequest(c1.getClusterName(), s2.getName(), null);
+    r = new ServiceRequest(c1.getClusterName(), s2.getName(), s2.getStackServiceName(), s2.getServiceGroupName(), null);
     resp = ServiceResourceProviderTest.getServices(controller, Collections.singleton(r));
     Assert.assertEquals(1, resp.size());
     Assert.assertEquals(s2.getName(), resp.iterator().next().getServiceName());
 
     try {
-      r = new ServiceRequest(c2.getClusterName(), s1.getName(), null);
+      r = new ServiceRequest(c2.getClusterName(), s1.getName(), s1.getStackServiceName(), s1.getServiceGroupName(), null);
       ServiceResourceProviderTest.getServices(controller, Collections.singleton(r));
       fail("Expected failure for invalid service");
     } catch (Exception e) {
       // Expected
     }
 
-    r = new ServiceRequest(c1.getClusterName(), null, "INSTALLED");
+    r = new ServiceRequest(c1.getClusterName(), null, null, "CORE", "INSTALLED");
     resp = ServiceResourceProviderTest.getServices(controller, Collections.singleton(r));
     Assert.assertEquals(2, resp.size());
 
-    r = new ServiceRequest(c2.getClusterName(), null, "INIT");
+    r = new ServiceRequest(c2.getClusterName(), null, null, "CORE", "INIT");
     resp = ServiceResourceProviderTest.getServices(controller, Collections.singleton(r));
     Assert.assertEquals(1, resp.size());
 
     ServiceRequest r1, r2, r3;
-    r1 = new ServiceRequest(c1.getClusterName(), null, "INSTALLED");
-    r2 = new ServiceRequest(c2.getClusterName(), null, "INIT");
-    r3 = new ServiceRequest(c2.getClusterName(), null, "INIT");
+    r1 = new ServiceRequest(c1.getClusterName(), null, null, "CORE", "INSTALLED");
+    r2 = new ServiceRequest(c2.getClusterName(), null, null, "CORE", "INIT");
+    r3 = new ServiceRequest(c2.getClusterName(), null, null, "CORE", "INIT");
 
     Set<ServiceRequest> reqs = new HashSet<ServiceRequest>();
     reqs.addAll(Arrays.asList(r1, r2, r3));
@@ -2382,7 +2382,7 @@ public class AmbariManagementControllerTest {
     clusters.addCluster(cluster1, new StackId("HDP-0.2"));
     Cluster c1 = clusters.getCluster(cluster1);
     c1.setDesiredStackVersion(new StackId("HDP-0.2"));
-    Service s1 = serviceFactory.createNew(c1, "HDFS");
+    Service s1 = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
     c1.addService(s1);
     s1.setDesiredState(State.INSTALLED);
     s1.persist();
@@ -2421,11 +2421,11 @@ public class AmbariManagementControllerTest {
     Cluster c1 = clusters.getCluster(cluster1);
     Cluster c2 = clusters.getCluster(cluster2);
 
-    Service s1 = serviceFactory.createNew(c1, "HDFS");
-    Service s2 = serviceFactory.createNew(c1, "MAPREDUCE");
-    Service s3 = serviceFactory.createNew(c1, "HBASE");
-    Service s4 = serviceFactory.createNew(c2, "HIVE");
-    Service s5 = serviceFactory.createNew(c2, "ZOOKEEPER");
+    Service s1 = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
+    Service s2 = serviceFactory.createNew(c1, "MAPREDUCE", "MAPREDUCE", "CORE");
+    Service s3 = serviceFactory.createNew(c1, "HBASE", "HBASE", "CORE");
+    Service s4 = serviceFactory.createNew(c2, "HIVE", "HIVE", "CORE");
+    Service s5 = serviceFactory.createNew(c2, "ZOOKEEPER", "ZOOKEEPER", "CORE");
 
     c1.addService(s1);
     c1.addService(s2);
@@ -2553,7 +2553,7 @@ public class AmbariManagementControllerTest {
     String host1 = getUniqueName();
 
     Cluster c1 = setupClusterWithHosts(cluster1, "HDP-0.1", Lists.newArrayList(host1), "centos5");
-    Service s1 = serviceFactory.createNew(c1, "HDFS");
+    Service s1 = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
     c1.addService(s1);
     s1.persist();
     ServiceComponent sc1 = serviceComponentFactory.createNew(s1, "DATANODE");
@@ -2960,9 +2960,9 @@ public class AmbariManagementControllerTest {
         }},
         "centos5");
 
-    Service s1 = serviceFactory.createNew(c1, "HDFS");
-    Service s2 = serviceFactory.createNew(c1, "MAPREDUCE");
-    Service s3 = serviceFactory.createNew(c1, "HBASE");
+    Service s1 = serviceFactory.createNew(c1, "HDFS", "HDFS", "CORE");
+    Service s2 = serviceFactory.createNew(c1, "MAPREDUCE", "MAPREDUCE", "CORE");
+    Service s3 = serviceFactory.createNew(c1, "HBASE", "HBASE", "CORE");
 
     c1.addService(s1);
     c1.addService(s2);
@@ -3206,7 +3206,7 @@ public class AmbariManagementControllerTest {
     ServiceRequest r;
 
     try {
-      r = new ServiceRequest(cluster1, serviceName,
+      r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE",
           State.INSTALLING.toString());
       reqs.clear();
       reqs.add(r);
@@ -3216,7 +3216,7 @@ public class AmbariManagementControllerTest {
       // Expected
     }
 
-    r = new ServiceRequest(cluster1, serviceName,
+    r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE",
         State.INSTALLED.toString());
     reqs.clear();
     reqs.add(r);
@@ -3261,9 +3261,9 @@ public class AmbariManagementControllerTest {
     ServiceRequest req1, req2;
     try {
       reqs.clear();
-      req1 = new ServiceRequest(cluster1, serviceName1,
+      req1 = new ServiceRequest(cluster1, serviceName1, serviceName1, "CORE",
           State.INSTALLED.toString());
-      req2 = new ServiceRequest(cluster2, serviceName2,
+      req2 = new ServiceRequest(cluster2, serviceName2, serviceName2, "CORE",
           State.INSTALLED.toString());
       reqs.add(req1);
       reqs.add(req2);
@@ -3275,9 +3275,9 @@ public class AmbariManagementControllerTest {
 
     try {
       reqs.clear();
-      req1 = new ServiceRequest(cluster1, serviceName1,
+      req1 = new ServiceRequest(cluster1, serviceName1, serviceName1,"CORE",
           State.INSTALLED.toString());
-      req2 = new ServiceRequest(cluster1, serviceName1,
+      req2 = new ServiceRequest(cluster1, serviceName1, serviceName1, "CORE",
           State.INSTALLED.toString());
       reqs.add(req1);
       reqs.add(req2);
@@ -3292,9 +3292,9 @@ public class AmbariManagementControllerTest {
 
     try {
       reqs.clear();
-      req1 = new ServiceRequest(cluster1, serviceName1,
+      req1 = new ServiceRequest(cluster1, serviceName1, serviceName1, "CORE",
           State.INSTALLED.toString());
-      req2 = new ServiceRequest(cluster1, serviceName2,
+      req2 = new ServiceRequest(cluster1, serviceName2, serviceName2, "CORE",
           State.STARTED.toString());
       reqs.add(req1);
       reqs.add(req2);
@@ -3404,7 +3404,7 @@ public class AmbariManagementControllerTest {
     ServiceRequest req1, req2;
     try {
       reqs.clear();
-      req1 = new ServiceRequest(cluster1, serviceName1,
+      req1 = new ServiceRequest(cluster1, serviceName1, serviceName1, "CORE",
           State.STARTED.toString());
       reqs.add(req1);
       ServiceResourceProviderTest.updateServices(controller, reqs, mapRequestProps, true, false);
@@ -3431,7 +3431,7 @@ public class AmbariManagementControllerTest {
 
     try {
       reqs.clear();
-      req1 = new ServiceRequest(cluster1, serviceName1,
+      req1 = new ServiceRequest(cluster1, serviceName1, serviceName1, "CORE",
           State.STARTED.toString());
       reqs.add(req1);
       ServiceResourceProviderTest.updateServices(controller, reqs, mapRequestProps, true, false);
@@ -3457,9 +3457,9 @@ public class AmbariManagementControllerTest {
     sch5.setState(State.INSTALLED);
 
     reqs.clear();
-    req1 = new ServiceRequest(cluster1, serviceName1,
+    req1 = new ServiceRequest(cluster1, serviceName1, serviceName1, "CORE",
         State.STARTED.toString());
-    req2 = new ServiceRequest(cluster1, serviceName2,
+    req2 = new ServiceRequest(cluster1, serviceName2, serviceName2, "CORE",
         State.STARTED.toString());
     reqs.add(req1);
     reqs.add(req2);
@@ -3545,9 +3545,9 @@ public class AmbariManagementControllerTest {
 
     // test no-op
     reqs.clear();
-    req1 = new ServiceRequest(cluster1, serviceName1,
+    req1 = new ServiceRequest(cluster1, serviceName1, serviceName1, "CORE",
         State.STARTED.toString());
-    req2 = new ServiceRequest(cluster1, serviceName2,
+    req2 = new ServiceRequest(cluster1, serviceName2, serviceName2, "CORE",
         State.STARTED.toString());
     reqs.add(req1);
     reqs.add(req2);
@@ -4292,10 +4292,10 @@ public class AmbariManagementControllerTest {
     cluster.addConfig(config2);
     cluster.addConfig(config3);
 
-    Service hdfs = cluster.addService("HDFS");
+    Service hdfs = cluster.addService("HDFS", "HDFS", "CORE");
     hdfs.persist();
 
-    Service mapred = cluster.addService("YARN");
+    Service mapred = cluster.addService("YARN", "YARN", "CORE");
     mapred.persist();
 
     hdfs.addServiceComponent(Role.HDFS_CLIENT.name()).persist();
@@ -4461,7 +4461,7 @@ public class AmbariManagementControllerTest {
     cluster.addConfig(config1);
     cluster.addConfig(config2);
 
-    Service hdfs = cluster.addService("HDFS");
+    Service hdfs = cluster.addService("HDFS", "HDFS", "CORE");
     hdfs.persist();
 
     hdfs.addServiceComponent(Role.HDFS_CLIENT.name()).persist();
@@ -4571,10 +4571,10 @@ public class AmbariManagementControllerTest {
     cluster.addDesiredConfig("_test", Collections.singleton(config1));
     cluster.addDesiredConfig("_test", Collections.singleton(config2));
 
-    Service hdfs = cluster.addService("HDFS");
+    Service hdfs = cluster.addService("HDFS", "HDFS", "CORE");
     hdfs.persist();
 
-    Service hive = cluster.addService("HIVE");
+    Service hive = cluster.addService("HIVE", "HIVE", "CORE");
     hive.persist();
 
     hdfs.addServiceComponent(Role.HDFS_CLIENT.name()).persist();
@@ -4858,8 +4858,8 @@ public class AmbariManagementControllerTest {
     cluster.addDesiredConfig("_test", Collections.singleton(config1));
     cluster.addDesiredConfig("_test", Collections.singleton(config2));
 
-    Service hdfs = cluster.addService("HDFS");
-    Service mapReduce = cluster.addService("MAPREDUCE");
+    Service hdfs = cluster.addService("HDFS", "HDFS", "CORE");
+    Service mapReduce = cluster.addService("MAPREDUCE", "MAPREDUCE", "CORE");
     hdfs.persist();
     mapReduce.persist();
 
@@ -5075,7 +5075,7 @@ public class AmbariManagementControllerTest {
             .getServiceComponentHost(host2));
 
     // Install
-    ServiceRequest r = new ServiceRequest(cluster1, serviceName,
+    ServiceRequest r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE",
         State.INSTALLED.toString());
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r);
@@ -5095,7 +5095,7 @@ public class AmbariManagementControllerTest {
     }
 
     // Start
-    r = new ServiceRequest(cluster1, serviceName,
+    r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE",
             State.STARTED.toString());
     requests.clear();
     requests.add(r);
@@ -5187,7 +5187,7 @@ public class AmbariManagementControllerTest {
     configVersions.put("typeC", "v2");
     configVersions.put("typeE", "v1");
     sReqs.clear();
-    sReqs.add(new ServiceRequest(cluster1, serviceName, null));
+    sReqs.add(new ServiceRequest(cluster1, serviceName, serviceName, "CORE", null));
     Assert.assertNull(ServiceResourceProviderTest.updateServices(controller, sReqs, mapRequestProps, true, false));
 
 
@@ -5336,7 +5336,7 @@ public class AmbariManagementControllerTest {
     configVersions.put("typeC", "v2");
     configVersions.put("typeE", "v1");
     sReqs.clear();
-    sReqs.add(new ServiceRequest(cluster1, serviceName, null));
+    sReqs.add(new ServiceRequest(cluster1, serviceName, serviceName, "CORE", null));
     Assert.assertNull(ServiceResourceProviderTest.updateServices(controller, sReqs, mapRequestProps, true, false));
 
     // update configs at SCH level
@@ -5402,7 +5402,7 @@ public class AmbariManagementControllerTest {
       host2, null);
 
     // Install
-    ServiceRequest r = new ServiceRequest(cluster1, serviceName,
+    ServiceRequest r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE",
       State.INSTALLED.toString());
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r);
@@ -5502,7 +5502,7 @@ public class AmbariManagementControllerTest {
     configVersions.put("core-site", "version1");
     configVersions.put("hdfs-site", "version1");
     sReqs.clear();
-    sReqs.add(new ServiceRequest(cluster1, serviceName, null));
+    sReqs.add(new ServiceRequest(cluster1, serviceName, serviceName, "CORE", null));
     Assert.assertNull(ServiceResourceProviderTest.updateServices(controller, sReqs, mapRequestProps, true, false));
 
     // Reconfigure S Level
@@ -5510,7 +5510,7 @@ public class AmbariManagementControllerTest {
     configVersions.put("core-site", "version122");
 
     sReqs.clear();
-    sReqs.add(new ServiceRequest(cluster1, serviceName, null));
+    sReqs.add(new ServiceRequest(cluster1, serviceName, serviceName, "CORE", null));
     Assert.assertNull(ServiceResourceProviderTest.updateServices(controller, sReqs, mapRequestProps, true, false));
 
     entityManager.clear();
@@ -5829,7 +5829,7 @@ public class AmbariManagementControllerTest {
     createServiceComponentHost(cluster1, null, componentName1,
         host2, null);
 
-    ServiceRequest r = new ServiceRequest(cluster1, serviceName, State.INSTALLED.toString());
+    ServiceRequest r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", State.INSTALLED.toString());
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r);
 
@@ -5865,7 +5865,7 @@ public class AmbariManagementControllerTest {
       }
     }
 
-    r = new ServiceRequest(cluster1, serviceName, State.STARTED.toString());
+    r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", State.STARTED.toString());
     requests.clear();
     requests.add(r);
 
@@ -6296,7 +6296,7 @@ public class AmbariManagementControllerTest {
 
     // Start Service
     ServiceRequest sr = new ServiceRequest(
-      cluster1, serviceName, State.STARTED.name());
+      cluster1, serviceName, serviceName, "CORE", State.STARTED.name());
     Set<ServiceRequest> setReqs = new HashSet<ServiceRequest>();
     setReqs.add(sr);
     RequestStatusResponse resp = ServiceResourceProviderTest.updateServices(controller,
@@ -6539,10 +6539,10 @@ public class AmbariManagementControllerTest {
     cluster.addConfig(config1);
     cluster.addConfig(config2);
 
-    Service hdfs = cluster.addService("HDFS");
+    Service hdfs = cluster.addService("HDFS", "HDFS", "CORE");
     hdfs.persist();
 
-    Service mapred = cluster.addService("YARN");
+    Service mapred = cluster.addService("YARN", "YARN", "CORE");
     mapred.persist();
 
     hdfs.addServiceComponent(Role.HDFS_CLIENT.name()).persist();
@@ -6648,10 +6648,10 @@ public class AmbariManagementControllerTest {
     cluster.addConfig(config1);
     cluster.addConfig(config2);
 
-    Service hdfs = cluster.addService("HDFS");
+    Service hdfs = cluster.addService("HDFS", "HDFS", "CORE");
     hdfs.persist();
 
-    Service mapred = cluster.addService("YARN");
+    Service mapred = cluster.addService("YARN", "YARN", "CORE");
     mapred.persist();
 
     hdfs.addServiceComponent(Role.HDFS_CLIENT.name()).persist();
@@ -6867,7 +6867,7 @@ public class AmbariManagementControllerTest {
       put("core-site", "version1");
       put("hdfs-site", "version1");
     }};
-    ServiceRequest sr = new ServiceRequest(cluster1, serviceName, null);
+    ServiceRequest sr = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", null);
     ServiceResourceProviderTest.updateServices(controller, Collections.singleton(sr), new HashMap<String,String>(), false, false);
 
     // Install
@@ -6920,7 +6920,7 @@ public class AmbariManagementControllerTest {
 
 
 
-    ServiceRequest r = new ServiceRequest(cluster1, serviceName, State.INSTALLED.toString());
+    ServiceRequest r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", State.INSTALLED.toString());
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r);
 
@@ -8225,7 +8225,7 @@ public class AmbariManagementControllerTest {
       .getServiceComponentHost(host2));
 
     // Install
-    ServiceRequest r = new ServiceRequest(cluster1, serviceName, State.INSTALLED.toString());
+    ServiceRequest r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", State.INSTALLED.toString());
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r);
 
@@ -8244,7 +8244,7 @@ public class AmbariManagementControllerTest {
     }
 
     // Start
-    r = new ServiceRequest(cluster1, serviceName, State.STARTED.toString());
+    r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", State.STARTED.toString());
     requests.clear();
     requests.add(r);
     ServiceResourceProviderTest.updateServices(controller, requests, mapRequestProps, true, false);
@@ -8289,7 +8289,7 @@ public class AmbariManagementControllerTest {
     }
 
     // Stop all services
-    r = new ServiceRequest(cluster1, serviceName, State.INSTALLED.toString());
+    r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", State.INSTALLED.toString());
     requests.clear();
     requests.add(r);
     ServiceResourceProviderTest.updateServices(controller, requests, mapRequestProps, true, false);
@@ -8492,7 +8492,7 @@ public class AmbariManagementControllerTest {
 
 
     // Install
-    ServiceRequest r = new ServiceRequest(cluster1, serviceName, State.INSTALLED.toString());
+    ServiceRequest r = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", State.INSTALLED.toString());
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r);
 
@@ -8590,7 +8590,7 @@ public class AmbariManagementControllerTest {
     sch3.setState(State.INSTALLED);
 
     // an UNKOWN failure will throw an exception
-    ServiceRequest req = new ServiceRequest(cluster1, serviceName1,
+    ServiceRequest req = new ServiceRequest(cluster1, serviceName1, serviceName1, "CORE",
         State.INSTALLED.toString());
     ServiceResourceProviderTest.updateServices(controller, Collections.singleton(req), Collections.<String, String>emptyMap(), true, false);
   }
@@ -9218,7 +9218,7 @@ public class AmbariManagementControllerTest {
       amc.createCluster(clusterRequest);
 
       Set<ServiceRequest> serviceRequests = new HashSet<ServiceRequest>();
-      serviceRequests.add(new ServiceRequest(cluster1, "HDFS", null));
+      serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null));
 
       ServiceResourceProviderTest.createServices(amc, serviceRequests);
 
@@ -9302,9 +9302,9 @@ public class AmbariManagementControllerTest {
       HostResourceProviderTest.createHosts(amc, hrs);
 
       Set<ServiceRequest> serviceRequests = new HashSet<ServiceRequest>();
-      serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "HDFS", null));
-      serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "MAPREDUCE2", null));
-      serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "YARN", null));
+      serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "HDFS", "HDFS", "CORE", null));
+      serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "MAPREDUCE2", "MAPREDUCE", "CORE", null));
+      serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "YARN", "YARN", "CORE", null));
 
       ServiceResourceProviderTest.createServices(amc, serviceRequests);
 
@@ -9383,8 +9383,8 @@ public class AmbariManagementControllerTest {
     amc.createCluster(clusterRequest);
 
     Set<ServiceRequest> serviceRequests = new HashSet<ServiceRequest>();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", null));
-    serviceRequests.add(new ServiceRequest(cluster1, "HIVE", null));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null));
+    serviceRequests.add(new ServiceRequest(cluster1, "HIVE", "HIVE", "CORE", null));
 
     ServiceResourceProviderTest.createServices(amc, serviceRequests);
 
@@ -9405,7 +9405,7 @@ public class AmbariManagementControllerTest {
     Assert.assertTrue(clusters.getCluster(cluster1).getDesiredConfigs().containsKey("hive-site"));
 
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", null));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null));
 
     ServiceResourceProviderTest.updateServices(amc, serviceRequests, mapRequestProps, true, false);
 
@@ -9435,7 +9435,7 @@ public class AmbariManagementControllerTest {
     amc.createHostComponents(componentHostRequests);
 
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "INSTALLED"));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", "INSTALLED"));
     ServiceResourceProviderTest.updateServices(amc, serviceRequests, mapRequestProps, true, false);
 
     Cluster cluster = clusters.getCluster(cluster1);
@@ -9502,7 +9502,7 @@ public class AmbariManagementControllerTest {
     componentHost.handleEvent(new ServiceComponentHostOpSucceededEvent(componentHost.getServiceComponentName(), componentHost.getHostName(), System.currentTimeMillis()));
 
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "STARTED"));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", "STARTED"));
 
     RequestStatusResponse response = ServiceResourceProviderTest.updateServices(amc, serviceRequests,
         mapRequestProps, true, false);
@@ -9564,14 +9564,14 @@ public class AmbariManagementControllerTest {
     // ServiceComponentHost remains in disabled after service stop
     assertEquals(sch.getServiceComponentName(),"DATANODE");
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "INSTALLED"));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", "INSTALLED"));
     ServiceResourceProviderTest.updateServices(amc, serviceRequests,
       mapRequestProps, true, false);
     assertEquals(State.DISABLED, sch.getState());
 
     // ServiceComponentHost remains in disabled after service start
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "STARTED"));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", "STARTED"));
     ServiceResourceProviderTest.updateServices(amc, serviceRequests,
       mapRequestProps, true, false);
     assertEquals(State.DISABLED, sch.getState());
@@ -9593,24 +9593,24 @@ public class AmbariManagementControllerTest {
     *Test remove service
     */
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "INSTALLED"));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", "INSTALLED"));
     ServiceResourceProviderTest.updateServices(amc, serviceRequests, mapRequestProps, true, false);
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, null, null));
+    serviceRequests.add(new ServiceRequest(cluster1, null, null, "CORE", null));
     org.junit.Assert.assertEquals(2, ServiceResourceProviderTest.getServices(amc, serviceRequests).size());
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", null));
-    serviceRequests.add(new ServiceRequest(cluster1, "HIVE", null));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null));
+    serviceRequests.add(new ServiceRequest(cluster1, "HIVE", "HIVE", "CORE", null));
     ServiceResourceProviderTest.deleteServices(amc, serviceRequests);
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, null, null));
+    serviceRequests.add(new ServiceRequest(cluster1, null, null, "CORE", null));
     org.junit.Assert.assertEquals(0, ServiceResourceProviderTest.getServices(amc, serviceRequests).size());
 
     /*
     *Test add service again
     */
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", null));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null));
 
     ServiceResourceProviderTest.createServices(amc, serviceRequests);
 
@@ -9627,7 +9627,7 @@ public class AmbariManagementControllerTest {
     amc.createConfiguration(configurationRequest);
     //Add configs to service
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", null));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", null));
     ServiceResourceProviderTest.updateServices(amc, serviceRequests, mapRequestProps, true, false);
     //Crate service components
     serviceComponentRequests = new HashSet<ServiceComponentRequest>();
@@ -9682,9 +9682,9 @@ public class AmbariManagementControllerTest {
     amc.createCluster(clusterRequest);
 
     Set<ServiceRequest> serviceRequests = new HashSet<ServiceRequest>();
-    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "HDFS", null));
-    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "MAPREDUCE2", null));
-    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "YARN", null));
+    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "HDFS", "HDFS", "CORE", null));
+    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "MAPREDUCE2", "MAPREDUCE", "CORE", null));
+    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "YARN", "YARN", "CORE", null));
 
     ServiceResourceProviderTest.createServices(amc, serviceRequests);
 
@@ -9715,9 +9715,9 @@ public class AmbariManagementControllerTest {
 
     //Install services
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "HDFS", State.INSTALLED.name()));
-    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "MAPREDUCE2", State.INSTALLED.name()));
-    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "YARN", State.INSTALLED.name()));
+    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "HDFS", "HDFS", "CORE", State.INSTALLED.name()));
+    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "MAPREDUCE2", "MAPREDUCE", "CORE", State.INSTALLED.name()));
+    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "YARN", "YARN", "CORE", State.INSTALLED.name()));
 
     ServiceResourceProviderTest.updateServices(amc, serviceRequests, mapRequestProps, true, false);
 
@@ -9739,9 +9739,9 @@ public class AmbariManagementControllerTest {
 
     //Start services
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "HDFS", State.STARTED.name()));
-    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "MAPREDUCE2", State.STARTED.name()));
-    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "YARN", State.STARTED.name()));
+    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "HDFS", "HDFS", "CORE", State.STARTED.name()));
+    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "MAPREDUCE2", "MAPREDUCE", "CORE", State.STARTED.name()));
+    serviceRequests.add(new ServiceRequest(CLUSTER_NAME, "YARN", "YARN", "CORE", State.STARTED.name()));
 
     RequestStatusResponse response = ServiceResourceProviderTest.updateServices(amc, serviceRequests,
         mapRequestProps, true, false);
@@ -9772,7 +9772,7 @@ public class AmbariManagementControllerTest {
     ServiceResponse response = createNiceMock(ServiceResponse.class);
 
     // requests
-    ServiceRequest request1 = new ServiceRequest("cluster1", "service1", null);
+    ServiceRequest request1 = new ServiceRequest("cluster1", "service1", "service1", "CORE", null);
 
     Set<ServiceRequest> setRequests = new HashSet<ServiceRequest>();
     setRequests.add(request1);
@@ -9817,7 +9817,7 @@ public class AmbariManagementControllerTest {
     Cluster cluster = createNiceMock(Cluster.class);
 
     // requests
-    ServiceRequest request1 = new ServiceRequest("cluster1", "service1", null);
+    ServiceRequest request1 = new ServiceRequest("cluster1", "service1", "service1", "CORE", null);
     Set<ServiceRequest> setRequests = new HashSet<ServiceRequest>();
     setRequests.add(request1);
 
@@ -9869,10 +9869,10 @@ public class AmbariManagementControllerTest {
     ServiceResponse response2 = createNiceMock(ServiceResponse.class);
 
     // requests
-    ServiceRequest request1 = new ServiceRequest("cluster1", "service1", null);
-    ServiceRequest request2 = new ServiceRequest("cluster1", "service2", null);
-    ServiceRequest request3 = new ServiceRequest("cluster1", "service3", null);
-    ServiceRequest request4 = new ServiceRequest("cluster1", "service4", null);
+    ServiceRequest request1 = new ServiceRequest("cluster1", "service1", "service1", "CORE", null);
+    ServiceRequest request2 = new ServiceRequest("cluster1", "service2", "service2", "CORE", null);
+    ServiceRequest request3 = new ServiceRequest("cluster1", "service3", "service3", "CORE", null);
+    ServiceRequest request4 = new ServiceRequest("cluster1", "service4", "service4", "CORE", null);
 
     Set<ServiceRequest> setRequests = new HashSet<ServiceRequest>();
     setRequests.add(request1);
@@ -9923,7 +9923,7 @@ public class AmbariManagementControllerTest {
 
     //Stopping HDFS service
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "INSTALLED"));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", "INSTALLED"));
     ServiceResourceProviderTest.updateServices(amc, serviceRequests, mapRequestProps, false,
         false);
 
@@ -9931,7 +9931,7 @@ public class AmbariManagementControllerTest {
     // test(HDFS_SERVICE_CHECK) won't run
     boolean runSmokeTest = false;
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "STARTED"));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", "STARTED"));
     response = ServiceResourceProviderTest.updateServices(amc, serviceRequests, mapRequestProps,
         runSmokeTest, false);
 
@@ -9946,7 +9946,7 @@ public class AmbariManagementControllerTest {
 
     //Stopping HDFS service
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "INSTALLED"));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", "INSTALLED"));
     ServiceResourceProviderTest.updateServices(amc, serviceRequests, mapRequestProps, false,
         false);
 
@@ -9954,7 +9954,7 @@ public class AmbariManagementControllerTest {
     //run_smoke_test flag is set, smoke test will be run
     runSmokeTest = true;
     serviceRequests.clear();
-    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "STARTED"));
+    serviceRequests.add(new ServiceRequest(cluster1, "HDFS", "HDFS", "CORE", "STARTED"));
     response = ServiceResourceProviderTest.updateServices(amc, serviceRequests, mapRequestProps,
         runSmokeTest, false);
 
@@ -9998,7 +9998,7 @@ public class AmbariManagementControllerTest {
       }},
       "centos5");
 
-    Service hdfs = c1.addService("HDFS");
+    Service hdfs = c1.addService("HDFS", "HDFS", "CORE");
     hdfs.persist();
     createServiceComponent(cluster1, "HDFS", "NAMENODE", State.INIT);
     createServiceComponent(cluster1, "HDFS", "DATANODE", State.INIT);
@@ -10196,7 +10196,7 @@ public class AmbariManagementControllerTest {
     MaintenanceStateHelper maintenanceStateHelper = MaintenanceStateHelperTest.getMaintenanceStateHelperInstance(clusters);
 
     // test updating a service
-    ServiceRequest sr = new ServiceRequest(cluster1, serviceName, null);
+    ServiceRequest sr = new ServiceRequest(cluster1, serviceName, serviceName, "CORE", null);
     sr.setMaintenanceState(MaintenanceState.ON.name());
     ServiceResourceProviderTest.updateServices(controller,
         Collections.singleton(sr), requestProperties, false, false,
@@ -10441,8 +10441,8 @@ public class AmbariManagementControllerTest {
     service2.setMaintenanceState(MaintenanceState.ON);
 
     Set<ServiceRequest> srs = new HashSet<ServiceRequest>();
-    srs.add(new ServiceRequest(cluster1, serviceName1, State.INSTALLED.name()));
-    srs.add(new ServiceRequest(cluster1, serviceName2, State.INSTALLED.name()));
+    srs.add(new ServiceRequest(cluster1, serviceName1, serviceName1, "CORE", State.INSTALLED.name()));
+    srs.add(new ServiceRequest(cluster1, serviceName2, serviceName2, "CORE", State.INSTALLED.name()));
     RequestStatusResponse rsr = ServiceResourceProviderTest.updateServices(controller, srs,
             requestProperties, false, false, maintenanceStateHelper);
 
@@ -10475,8 +10475,8 @@ public class AmbariManagementControllerTest {
     h1.setMaintenanceState(cluster.getClusterId(), MaintenanceState.ON);
 
     srs = new HashSet<ServiceRequest>();
-    srs.add(new ServiceRequest(cluster1, serviceName1, State.INSTALLED.name()));
-    srs.add(new ServiceRequest(cluster1, serviceName2, State.INSTALLED.name()));
+    srs.add(new ServiceRequest(cluster1, serviceName1, serviceName1, "CORE", State.INSTALLED.name()));
+    srs.add(new ServiceRequest(cluster1, serviceName2, serviceName2, "CORE", State.INSTALLED.name()));
 
     rsr = ServiceResourceProviderTest.updateServices(controller, srs, requestProperties,
             false, false, maintenanceStateHelper);
@@ -10490,7 +10490,7 @@ public class AmbariManagementControllerTest {
 
     service2.setMaintenanceState(MaintenanceState.ON);
 
-    ServiceRequest sr = new ServiceRequest(cluster1, serviceName2, State.INSTALLED.name());
+    ServiceRequest sr = new ServiceRequest(cluster1, serviceName2, serviceName2, "CORE", State.INSTALLED.name());
     rsr = ServiceResourceProviderTest.updateServices(controller,
         Collections.singleton(sr), requestProperties, false, false, maintenanceStateHelper);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java
index fc39521..6368165 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java
@@ -201,7 +201,7 @@ public class BackgroundCustomCommandExecutionTest {
     if (desiredState != null) {
       dStateStr = desiredState.toString();
     }
-    ServiceRequest r1 = new ServiceRequest(clusterName, serviceName, dStateStr);
+    ServiceRequest r1 = new ServiceRequest(clusterName, serviceName, serviceName, "CORE", dStateStr);
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r1);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/RefreshYarnCapacitySchedulerReleaseConfigTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/RefreshYarnCapacitySchedulerReleaseConfigTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/RefreshYarnCapacitySchedulerReleaseConfigTest.java
index 179f658..5324ce9 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/RefreshYarnCapacitySchedulerReleaseConfigTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/RefreshYarnCapacitySchedulerReleaseConfigTest.java
@@ -202,7 +202,7 @@ public class RefreshYarnCapacitySchedulerReleaseConfigTest {
     if (desiredState != null) {
       dStateStr = desiredState.toString();
     }
-    ServiceRequest r1 = new ServiceRequest(clusterName, serviceName, dStateStr);
+    ServiceRequest r1 = new ServiceRequest(clusterName, serviceName, serviceName, "CORE", dStateStr);
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r1);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java
index 7ec6e66..ac6d4ce 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java
@@ -231,13 +231,13 @@ public class ComponentResourceProviderTest {
     expect(service.getServiceComponents()).andReturn(serviceComponentMap).anyTimes();
 
     expect(serviceComponent1.convertToResponse()).andReturn(
-      new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component100", null, "", 1, 1, 0,
+      new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component100", null, "", 1, 1, 0, 0,
               true /* recovery enabled */, "Component100 Client"));
     expect(serviceComponent2.convertToResponse()).andReturn(
-      new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component101", null, "", 1, 1, 0,
+      new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component101", null, "", 1, 1, 0, 0,
               false /* recovery not enabled */, "Component101 Client"));
     expect(serviceComponent3.convertToResponse()).andReturn(
-      new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component102", null, "", 1, 1, 0,
+      new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component102", null, "", 1, 1, 0, 0,
               true /* recovery enabled */, "Component102 Client"));
 
     expect(ambariMetaInfo.getComponent((String) anyObject(),
@@ -376,13 +376,13 @@ public class ComponentResourceProviderTest {
     expect(component3Info.getCategory()).andReturn(null);
 
     expect(serviceComponent1.convertToResponse()).andReturn(
-      new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component101", null, "", 1, 0, 1,
+      new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component101", null, "", 1, 0, 1, 0,
               false /* recovery not enabled */, "Component101 Client"));
     expect(serviceComponent2.convertToResponse()).andReturn(
-      new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component102", null, "", 1, 0, 1,
+      new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component102", null, "", 1, 0, 1, 0,
               false /* recovery not enabled */, "Component102 Client"));
     expect(serviceComponent3.convertToResponse()).andReturn(
-      new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component103", null, "", 1, 0, 1,
+      new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component103", null, "", 1, 0, 1, 0,
               false /* recovery not enabled */, "Component103 Client"));
     expect(serviceComponent1.getDesiredState()).andReturn(State.INSTALLED).anyTimes();
     expect(serviceComponent2.getDesiredState()).andReturn(State.INSTALLED).anyTimes();
@@ -683,7 +683,7 @@ public class ComponentResourceProviderTest {
     expect(component1Info.getCategory()).andReturn(null);
 
     expect(serviceComponent1.convertToResponse()).andReturn(
-        new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component101", null, "", 1, 0, 1,
+        new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component101", null, "", 1, 0, 1, 0,
             false /* recovery not enabled */, "Component101 Client"));
     expect(serviceComponent1.getDesiredState()).andReturn(State.INSTALLED).anyTimes();
 
@@ -753,7 +753,7 @@ public class ComponentResourceProviderTest {
 
     // requests
     ServiceComponentRequest request1 = new ServiceComponentRequest("cluster1", "service1", "component1",
-        null, String.valueOf(true /* recovery enabled */));
+        null, null, String.valueOf(true /* recovery enabled */));
 
     Set<ServiceComponentRequest> setRequests = new HashSet<ServiceComponentRequest>();
     setRequests.add(request1);
@@ -813,15 +813,15 @@ public class ComponentResourceProviderTest {
 
     // requests
     ServiceComponentRequest request1 = new ServiceComponentRequest("cluster1", "service1", "component1",
-        null, String.valueOf(true /* recovery enabled */));
+        null, null, String.valueOf(true /* recovery enabled */));
     ServiceComponentRequest request2 = new ServiceComponentRequest("cluster1", "service1", "component2",
-        null, String.valueOf(true /* recovery enabled */));
+        null, null, String.valueOf(true /* recovery enabled */));
     ServiceComponentRequest request3 = new ServiceComponentRequest("cluster1", "service1", "component3",
-        null, String.valueOf(true /* recovery enabled */));
+        null, null, String.valueOf(true /* recovery enabled */));
     ServiceComponentRequest request4 = new ServiceComponentRequest("cluster1", "service1", "component4",
-        null, String.valueOf(true /* recovery enabled */));
-    ServiceComponentRequest request5 = new ServiceComponentRequest("cluster1", "service2", null, null,
-              String.valueOf(true /* recovery enabled */));
+        null, null, String.valueOf(true /* recovery enabled */));
+    ServiceComponentRequest request5 = new ServiceComponentRequest("cluster1", "service2", null, null, null,
+        String.valueOf(true /* recovery enabled */));
 
     Set<ServiceComponentRequest> setRequests = new HashSet<ServiceComponentRequest>();
     setRequests.add(request1);
@@ -851,8 +851,8 @@ public class ComponentResourceProviderTest {
     expect(component4Info.getCategory()).andReturn(null);
 
     expect(service.getName()).andReturn("service1").anyTimes();
-    expect(service.getServiceComponent("component1")).andThrow(new ServiceComponentNotFoundException("cluster1", "service1", "component1"));
-    expect(service.getServiceComponent("component2")).andThrow(new ServiceComponentNotFoundException("cluster1", "service1", "component2"));
+    expect(service.getServiceComponent("component1")).andThrow(new ServiceComponentNotFoundException("cluster1", "service1", "service1", "CORE", "component1"));
+    expect(service.getServiceComponent("component2")).andThrow(new ServiceComponentNotFoundException("cluster1", "service1", "service1", "CORE", "component2"));
     expect(service.getServiceComponent("component3")).andReturn(component1);
     expect(service.getServiceComponent("component4")).andReturn(component2);
 
@@ -905,7 +905,7 @@ public class ComponentResourceProviderTest {
 
     // requests
     ServiceComponentRequest request1 = new ServiceComponentRequest("cluster1", "service1", "component1",
-        null, String.valueOf(true /* recovery enabled */));
+        null, null, String.valueOf(true /* recovery enabled */));
 
     Set<ServiceComponentRequest> setRequests = new HashSet<ServiceComponentRequest>();
     setRequests.add(request1);
@@ -921,7 +921,7 @@ public class ComponentResourceProviderTest {
     expect(clusters.getCluster("cluster1")).andReturn(cluster);
     expect(cluster.getService("service1")).andReturn(service);
     expect(service.getServiceComponent("component1")).andThrow(
-        new ServiceComponentNotFoundException("cluster1", "service1", "component1"));
+        new ServiceComponentNotFoundException("cluster1", "service1", "service1", "CORE", "component1"));
     // replay mocks
     replay(maintHelper, injector, clusters, cluster, service);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/JMXHostProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/JMXHostProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/JMXHostProviderTest.java
index a6e5501..4f86c8c 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/JMXHostProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/JMXHostProviderTest.java
@@ -107,7 +107,7 @@ public class JMXHostProviderTest {
     if (desiredState != null) {
       dStateStr = desiredState.toString();
     }
-    ServiceRequest r1 = new ServiceRequest(clusterName, serviceName, dStateStr);
+    ServiceRequest r1 = new ServiceRequest(clusterName, serviceName, serviceName, "CORE", dStateStr);
     Set<ServiceRequest> requests = new HashSet<ServiceRequest>();
     requests.add(r1);
     ServiceResourceProviderTest.createServices(controller, requests);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ServiceResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ServiceResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ServiceResourceProviderTest.java
index 84f8124..8555b62 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ServiceResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ServiceResourceProviderTest.java
@@ -119,7 +119,7 @@ public class ServiceResourceProviderTest {
     expect(managementController.getAmbariMetaInfo()).andReturn(ambariMetaInfo);
     expect(managementController.getServiceFactory()).andReturn(serviceFactory);
 
-    expect(serviceFactory.createNew(cluster, "Service100")).andReturn(service);
+    expect(serviceFactory.createNew(cluster, "Service100", "Service100", "CORE")).andReturn(service);
 
     expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes();
 
@@ -145,6 +145,7 @@ public class ServiceResourceProviderTest {
     // add properties to the request map
     properties.put(ServiceResourceProvider.SERVICE_CLUSTER_NAME_PROPERTY_ID, "Cluster100");
     properties.put(ServiceResourceProvider.SERVICE_SERVICE_NAME_PROPERTY_ID, "Service100");
+    properties.put(ServiceResourceProvider.SERVICE_STACK_SERVICE_NAME_PROPERTY_ID, "Service100");
     properties.put(ServiceResourceProvider.SERVICE_SERVICE_STATE_PROPERTY_ID, "INIT");
 
     propertySet.add(properties);
@@ -254,6 +255,7 @@ public class ServiceResourceProviderTest {
 
     propertyIds.add(ServiceResourceProvider.SERVICE_CLUSTER_NAME_PROPERTY_ID);
     propertyIds.add(ServiceResourceProvider.SERVICE_SERVICE_NAME_PROPERTY_ID);
+    propertyIds.add(ServiceResourceProvider.SERVICE_STACK_SERVICE_NAME_PROPERTY_ID);
 
     // create the request
     Predicate predicate = new PredicateBuilder().property(ServiceResourceProvider.SERVICE_CLUSTER_NAME_PROPERTY_ID).equals("Cluster100").toPredicate();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderHDP22Test.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderHDP22Test.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderHDP22Test.java
index a4a3108..a3ee16b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderHDP22Test.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderHDP22Test.java
@@ -226,7 +226,7 @@ public class UpgradeResourceProviderHDP22Test {
     clusters.mapHostToCluster("h1", "c1");
 
     // add a single HIVE server
-    Service service = cluster.addService("HIVE");
+    Service service = cluster.addService("HIVE", "HIVE", "CORE");
     service.setDesiredStackVersion(cluster.getDesiredStackVersion());
     service.persist();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
index 8f53f6a..85e0cea 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
@@ -223,7 +223,7 @@ public class UpgradeResourceProviderTest {
     clusters.mapHostToCluster("h1", "c1");
 
     // add a single ZK server
-    Service service = cluster.addService("ZOOKEEPER");
+    Service service = cluster.addService("ZOOKEEPER", "ZOOKEEPER", "CORE");
     service.setDesiredStackVersion(cluster.getDesiredStackVersion());
     service.persist();
 
@@ -713,7 +713,7 @@ public class UpgradeResourceProviderTest {
     Cluster cluster = clusters.getCluster("c1");
 
     // add additional service for the test
-    Service service = cluster.addService("HIVE");
+    Service service = cluster.addService("HIVE", "HIVE", "CORE");
     service.setDesiredStackVersion(cluster.getDesiredStackVersion());
     service.persist();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeSummaryResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeSummaryResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeSummaryResourceProviderTest.java
index eccc1ed..915586e 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeSummaryResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeSummaryResourceProviderTest.java
@@ -175,7 +175,7 @@ public class UpgradeSummaryResourceProviderTest {
     clusters.mapHostToCluster("h1", "c1");
 
     // add a single ZOOKEEPER server
-    Service service = cluster.addService("ZOOKEEPER");
+    Service service = cluster.addService("ZOOKEEPER", "ZOOKEEPER", "CORE");
     service.setDesiredStackVersion(cluster.getDesiredStackVersion());
     service.persist();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProviderTest.java
index 88b00ca..1f3cb52 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProviderTest.java
@@ -360,7 +360,7 @@ public class UserPrivilegeResourceProviderTest extends EasyMockSupport {
     ViewInstanceEntity viewInstanceEntity = createMock(ViewInstanceEntity.class);
     expect(viewInstanceEntity.getViewEntity()).andReturn(viewEntity).atLeastOnce();
     expect(viewInstanceEntity.getName()).andReturn("Test View").atLeastOnce();
-    expect(viewInstanceEntity.getClusterHandle()).andReturn("c1").atLeastOnce();
+    expect(viewInstanceEntity.getClusterHandle()).andReturn(1L).atLeastOnce();
     expect(viewInstanceEntity.getResource()).andReturn(resourceEntity).atLeastOnce();
 
     PrivilegeEntity privilegeEntityViewWithClusterAdminAccess = createMock(PrivilegeEntity.class);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProviderTest.java
index 1044570..f6614dc 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProviderTest.java
@@ -91,7 +91,7 @@ public class ViewInstanceResourceProviderTest {
     expect(viewregistry.checkAdmin()).andReturn(true);
     expect(viewregistry.checkAdmin()).andReturn(false);
 
-    expect(viewInstanceEntity.getClusterHandle()).andReturn("c1");
+    expect(viewInstanceEntity.getClusterHandle()).andReturn(1L);
 
     replay(viewregistry, viewEntity, viewInstanceEntity);
 
@@ -102,7 +102,7 @@ public class ViewInstanceResourceProviderTest {
     Map<String, Object> props = properties.get("ViewInstanceInfo");
     assertNotNull(props);
     assertEquals(1, props.size());
-    assertEquals("c1", props.get("cluster_handle"));
+    assertEquals(1L, props.get("cluster_handle"));
 
     props = properties.get("ViewInstanceInfo/properties");
     assertNotNull(props);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/state/GeneralServiceCalculatedStateTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/state/GeneralServiceCalculatedStateTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/state/GeneralServiceCalculatedStateTest.java
index 710c723..b88f58d 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/state/GeneralServiceCalculatedStateTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/state/GeneralServiceCalculatedStateTest.java
@@ -74,7 +74,7 @@ public abstract class GeneralServiceCalculatedStateTest {
     clusters.addCluster(clusterName, stack211);
     cluster = clusters.getCluster(clusterName);
 
-    service = cluster.addService(getServiceName());
+    service = cluster.addService(getServiceName(), getServiceName(), "CORE");
     service.setDesiredStackVersion(cluster.getDesiredStackVersion());
     service.persist();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/events/EventsTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/events/EventsTest.java b/ambari-server/src/test/java/org/apache/ambari/server/events/EventsTest.java
index ce86f83..f84d0c6 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/events/EventsTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/events/EventsTest.java
@@ -381,7 +381,7 @@ public class EventsTest {
    */
   private void installHdfsService() throws Exception {
     String serviceName = "HDFS";
-    Service service = m_serviceFactory.createNew(m_cluster, serviceName);
+    Service service = m_serviceFactory.createNew(m_cluster, serviceName, serviceName, "CORE");
     service.persist();
     service = m_cluster.getService(serviceName);
     Assert.assertNotNull(service);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListenerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListenerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListenerTest.java
index 9135732..451503a 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListenerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListenerTest.java
@@ -454,7 +454,7 @@ public class HostVersionOutOfSyncListenerTest {
                           ) throws AmbariException {
     StackId stackIdObj = new StackId(stackId);
     cl.setDesiredStackVersion(stackIdObj);
-    cl.addService(serviceName);
+    cl.addService(serviceName, serviceName, "CORE");
 
     for (Map.Entry<String, List<Integer>> component : topology.entrySet()) {
 
@@ -470,7 +470,7 @@ public class HostVersionOutOfSyncListenerTest {
       }
 
       ServiceInstalledEvent event = new ServiceInstalledEvent(cl.getClusterId(),
-          stackIdObj.getStackName(), stackIdObj.getStackVersion(), serviceName);
+          stackIdObj.getStackName(), stackIdObj.getStackVersion(), serviceName, serviceName, "CORE");
       m_eventPublisher.publish(event);
     }
   }
@@ -487,7 +487,7 @@ public class HostVersionOutOfSyncListenerTest {
           .getServiceComponent(componentName), hostName));
       ServiceComponentInstalledEvent event = new ServiceComponentInstalledEvent(cl.getClusterId(),
           stackIdObj.getStackName(), stackIdObj.getStackVersion(),
-          serviceName, componentName, hostName, false /* recovery not enabled */);
+          serviceName, serviceName, "CORE", componentName, hostName, false /* recovery not enabled */);
       m_eventPublisher.publish(event);
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
index 1bfcfb9..ffb71a5 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
@@ -420,7 +420,7 @@ public class OrmTestHelper {
       ServiceFactory serviceFactory, ServiceComponentFactory componentFactory,
       ServiceComponentHostFactory schFactory, String hostName) throws Exception {
     String serviceName = "HDFS";
-    Service service = serviceFactory.createNew(cluster, serviceName);
+    Service service = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
     service.persist();
     service = cluster.getService(serviceName);
     assertNotNull(service);
@@ -465,7 +465,7 @@ public class OrmTestHelper {
       ServiceFactory serviceFactory, ServiceComponentFactory componentFactory,
       ServiceComponentHostFactory schFactory, String hostName) throws Exception {
     String serviceName = "YARN";
-    Service service = serviceFactory.createNew(cluster, serviceName);
+    Service service = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
     service.persist();
     service = cluster.getService(serviceName);
     assertNotNull(service);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AuthorizationHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AuthorizationHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AuthorizationHelperTest.java
index 9c59aab..9f38841 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AuthorizationHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AuthorizationHelperTest.java
@@ -360,7 +360,7 @@ public class AuthorizationHelperTest  extends EasyMockSupport {
     PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
 
     ViewInstanceEntity viewInstanceEntity = createNiceMock(ViewInstanceEntity.class);
-    expect(viewInstanceEntity.getClusterHandle()).andReturn("c1").anyTimes();
+    expect(viewInstanceEntity.getClusterHandle()).andReturn(1L).anyTimes();
 
     PrivilegeEntity privilegeEntity = createNiceMock(PrivilegeEntity.class);
     PrincipalEntity principalEntity = createNiceMock(PrincipalEntity.class);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ComponentVersionCheckActionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ComponentVersionCheckActionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ComponentVersionCheckActionTest.java
index 207b4c7..44e21d2 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ComponentVersionCheckActionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ComponentVersionCheckActionTest.java
@@ -375,7 +375,7 @@ public class ComponentVersionCheckActionTest {
     try {
       service = cluster.getService(serviceName);
     } catch (ServiceNotFoundException e) {
-      service = serviceFactory.createNew(cluster, serviceName);
+      service = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
       cluster.addService(service);
       service.persist();
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ConfigureActionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ConfigureActionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ConfigureActionTest.java
index be0aeef..b4b9d90 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ConfigureActionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ConfigureActionTest.java
@@ -1750,7 +1750,7 @@ public class ConfigureActionTest {
     try {
       service = cluster.getService(serviceName);
     } catch (ServiceNotFoundException e) {
-      service = serviceFactory.createNew(cluster, serviceName);
+      service = serviceFactory.createNew(cluster, serviceName, serviceName, "CORE");
       cluster.addService(service);
       service.persist();
     }


[12/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/.bowerrc
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/.bowerrc b/contrib/views/hive-next/src/main/resources/ui/hive-web/.bowerrc
new file mode 100644
index 0000000..959e169
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/.bowerrc
@@ -0,0 +1,4 @@
+{
+  "directory": "bower_components",
+  "analytics": false
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/.editorconfig
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/.editorconfig b/contrib/views/hive-next/src/main/resources/ui/hive-web/.editorconfig
new file mode 100644
index 0000000..47c5438
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/.editorconfig
@@ -0,0 +1,34 @@
+# EditorConfig helps developers define and maintain consistent
+# coding styles between different editors and IDEs
+# editorconfig.org
+
+root = true
+
+
+[*]
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = space
+indent_size = 2
+
+[*.js]
+indent_style = space
+indent_size = 2
+
+[*.hbs]
+insert_final_newline = false
+indent_style = space
+indent_size = 2
+
+[*.css]
+indent_style = space
+indent_size = 2
+
+[*.html]
+indent_style = space
+indent_size = 2
+
+[*.{diff,md}]
+trim_trailing_whitespace = false

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/.ember-cli
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/.ember-cli b/contrib/views/hive-next/src/main/resources/ui/hive-web/.ember-cli
new file mode 100644
index 0000000..3da2738
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/.ember-cli
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+{
+  /**
+    Ember CLI sends analytics information by default. The data is completely
+    anonymous, but there are times when you might want to disable this behavior.
+
+    Setting `disableAnalytics` to true will prevent any data from being sent.
+  */
+  "disableAnalytics": true
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/.gitignore
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/.gitignore b/contrib/views/hive-next/src/main/resources/ui/hive-web/.gitignore
new file mode 100644
index 0000000..e1b6b28
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/.gitignore
@@ -0,0 +1,37 @@
+# Numerous always-ignore extensions
+*.diff
+*.err
+*.orig
+*.log
+*.rej
+*.swo
+*.swp
+*.vi
+*~
+*.sass-cache
+
+# OS or Editor folders
+.DS_Store
+.cache
+.project
+.settings
+.tmproj
+dist
+nbproject
+Thumbs.db
+
+# NPM packages folder.
+node_modules/
+
+bower_components/
+
+node/
+
+# Brunch folder for temporary files.
+tmp/
+
+public/
+
+_generators/
+
+coverage.json

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/.jshintrc
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/.jshintrc b/contrib/views/hive-next/src/main/resources/ui/hive-web/.jshintrc
new file mode 100644
index 0000000..0195538
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/.jshintrc
@@ -0,0 +1,33 @@
+{
+  "predef": [
+    "document",
+    "window",
+    "-Promise",
+    "d3"
+  ],
+  "browser" : true,
+  "boss" : true,
+  "curly": true,
+  "debug": false,
+  "devel": true,
+  "eqeqeq": false,
+  "evil": true,
+  "forin": false,
+  "immed": false,
+  "laxbreak": false,
+  "newcap": true,
+  "noarg": true,
+  "noempty": false,
+  "nonew": false,
+  "nomen": false,
+  "onevar": false,
+  "plusplus": false,
+  "regexp": false,
+  "undef": true,
+  "sub": true,
+  "strict": false,
+  "white": false,
+  "eqnull": true,
+  "esnext": true,
+  "unused": true
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/.travis.yml
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/.travis.yml b/contrib/views/hive-next/src/main/resources/ui/hive-web/.travis.yml
new file mode 100644
index 0000000..5d96e28
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/.travis.yml
@@ -0,0 +1,38 @@
+# 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.
+
+---
+language: node_js
+node_js:
+  - "0.12"
+
+sudo: false
+
+cache:
+  directories:
+    - node_modules
+
+before_install:
+  - "npm config set spin false"
+  - "npm install -g npm@^2"
+
+install:
+  - npm install -g bower
+  - npm install
+  - bower install
+
+script:
+  - npm test

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/Brocfile.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/Brocfile.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/Brocfile.js
new file mode 100644
index 0000000..318d1f8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/Brocfile.js
@@ -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.
+ */
+
+/* global require, module */
+
+var EmberApp = require('ember-cli/lib/broccoli/ember-app');
+
+var app = new EmberApp({
+  autoprefixer: {
+    browsers: ['last 3 version']
+  },
+  'ember-cli-selectize': {
+    //valid values are `default`, `bootstrap2`, `bootstrap3` or false
+    'theme': 'bootstrap3'
+  },
+  vendorFiles: {
+    'handlebars.js': null
+  },
+  hinting: false
+});
+
+app.import('bower_components/ember/ember-template-compiler.js');
+app.import('bower_components/bootstrap/dist/js/bootstrap.js');
+app.import('bower_components/bootstrap/dist/css/bootstrap.css');
+app.import('bower_components/bootstrap/dist/css/bootstrap.css.map', {
+  destDir: 'assets'
+});
+
+app.import('bower_components/ember-i18n/lib/i18n.js');
+app.import('bower_components/ember-i18n/lib/i18n-plurals.js');
+
+app.import('vendor/codemirror/codemirror-min.js');
+app.import('vendor/codemirror/sql-hint.js');
+app.import('vendor/codemirror/show-hint.js');
+app.import('vendor/codemirror/codemirror.css');
+app.import('vendor/codemirror/show-hint.css');
+app.import('vendor/dagre.min.js');
+
+module.exports = app.toTree();

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/README.md
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/README.md b/contrib/views/hive-next/src/main/resources/ui/hive-web/README.md
new file mode 100644
index 0000000..2237863
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/README.md
@@ -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](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.
+-->

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/application.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/application.js
new file mode 100644
index 0000000..34caa8a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/application.js
@@ -0,0 +1,46 @@
+/**
+ * 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.
+ */
+
+import DS from 'ember-data';
+import constants from 'hive/utils/constants';
+
+export default DS.RESTAdapter.extend({
+  headers: {
+    'X-Requested-By': 'ambari',
+    'Content-Type': 'application/json'
+    //,'Authorization': 'Basic YWRtaW46YWRtaW4='
+  },
+
+  buildURL: function () {
+    var version = constants.adapter.version,
+        instanceName = constants.adapter.instance;
+
+    var params = window.location.pathname.split('/').filter(function (param) {
+      return !!param;
+    });
+
+    if (params[params.length - 3] === 'HIVE') {
+      version = params[params.length - 2];
+      instanceName = params[params.length - 1];
+    }
+
+    var prefix = constants.adapter.apiPrefix + version + constants.adapter.instancePrefix + instanceName;
+    var url = this._super.apply(this, arguments);
+    return prefix + url;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/database.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/database.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/database.js
new file mode 100644
index 0000000..cdbd43b
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/database.js
@@ -0,0 +1,25 @@
+/**
+ * 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.
+ */
+
+import application from './application';
+
+export default application.extend({
+  pathForType: function (type) {
+    return 'resources/ddl/' + type;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/file-upload.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/file-upload.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/file-upload.js
new file mode 100644
index 0000000..1bd8eee
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/file-upload.js
@@ -0,0 +1,31 @@
+/**
+ * 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.
+ */
+
+import EmberUploader from 'ember-uploader';
+import Ember from 'ember';
+
+export default EmberUploader.Uploader.extend({
+  headers: {},
+
+  // Override
+  _ajax: function(settings) {
+    settings = Ember.merge(settings, this.getProperties('headers'));
+    console.log("_ajax : settings: " + JSON.stringify(settings));
+    return this._super(settings);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/file.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/file.js
new file mode 100644
index 0000000..47894c1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/file.js
@@ -0,0 +1,26 @@
+/**
+ * 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.
+ */
+
+import application from './application';
+import constants from 'hive/utils/constants';
+
+export default application.extend({
+  pathForType: function (type) {
+    return constants.adapter.resourcePrefix + type;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/upload-table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/upload-table.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/upload-table.js
new file mode 100644
index 0000000..ef4df43
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/adapters/upload-table.js
@@ -0,0 +1,93 @@
+/**
+ * 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.
+ */
+
+import EmberUploader from 'ember-uploader';
+import Ember from 'ember';
+import application from './application';
+import FileUploader from './file-upload';
+
+export default application.extend({
+
+  buildUploadURL: function (path) {
+    return this.buildURL() + "/resources/upload/" + path;
+  },
+
+  uploadFiles: function (path, files, extras) {
+    var uploadUrl = this.buildUploadURL(path);
+
+    console.log("uplaoder : uploadURL : ", uploadUrl);
+    console.log("uploader : extras : ", extras);
+    console.log("uploader : files : ", files);
+
+    var hdrs = Ember.$.extend(true, {},this.get('headers'));
+    delete hdrs['Content-Type'];
+    var uploader = FileUploader.create({
+      headers: hdrs,
+      url: uploadUrl
+    });
+
+    if (!Ember.isEmpty(files)) {
+      var promise = uploader.upload(files[0], extras);
+      return promise;
+    }
+  },
+
+  createTable: function (tableData) {
+    console.log("creating table with data :", tableData);
+    return this.doPost("createTable",tableData);
+  },
+
+  insertIntoTable: function(insertData){
+    console.log("inserting into table with data : ", insertData);
+    return this.doPost("insertIntoTable",insertData);
+  },
+
+  deleteTable: function(deleteData){
+    console.log("delete table with info : ", deleteData);
+    return this.doPost("deleteTable",deleteData);
+  },
+
+  doPost : function(path,inputData){
+    var self = this;
+    return new Ember.RSVP.Promise(function(resolve,reject){
+                 Ember.$.ajax({
+                     url :  self.buildUploadURL(path),
+                     type : 'post',
+                     data: JSON.stringify(inputData),
+                     headers: self.get('headers'),
+                     dataType : 'json'
+                 }).done(function(data) {
+                     console.log( "inside done : data : ", data );
+                     resolve(data);
+                 }).fail(function(error) {
+                     console.log( "inside fail error :  ", error );
+                     reject(error);
+                 });
+              });
+  },
+
+  previewFromHDFS : function(previewFromHdfsData){
+    console.log("preview from hdfs with info : ", previewFromHdfsData);
+    return this.doPost("previewFromHdfs",previewFromHdfsData)
+  },
+
+  uploadFromHDFS : function(uploadFromHdfsData){
+    console.log("upload from hdfs with info : ", uploadFromHdfsData);
+    return this.doPost("uploadFromHDFS",uploadFromHdfsData)
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/app.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/app.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/app.js
new file mode 100644
index 0000000..f35a5a3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/app.js
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import Resolver from 'ember/resolver';
+import loadInitializers from 'ember/load-initializers';
+import config from './config/environment';
+
+Ember.MODEL_FACTORY_INJECTIONS = true;
+
+var App = Ember.Application.extend({
+  modulePrefix: config.modulePrefix,
+  podModulePrefix: config.podModulePrefix,
+  Resolver: Resolver
+});
+
+loadInitializers(App, config.modulePrefix);
+
+export default App;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/alert-message-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/alert-message-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/alert-message-widget.js
new file mode 100644
index 0000000..565d93d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/alert-message-widget.js
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  actions: {
+    remove: function () {
+      this.sendAction('removeMessage', this.get('message'));
+    },
+
+    toggleMessage: function () {
+      this.toggleProperty('message.isExpanded');
+
+      if (!this.get('message.isExpanded')) {
+        this.sendAction('removeLater', this.get('message'));
+      }
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/collapsible-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/collapsible-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/collapsible-widget.js
new file mode 100644
index 0000000..eb174ab
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/collapsible-widget.js
@@ -0,0 +1,38 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  tagName: 'collapsible',
+
+  actions: {
+    toggle: function () {
+      this.toggleProperty('isExpanded');
+
+      if (this.get('isExpanded')) {
+        this.sendAction('expanded', this.get('heading'), this.get('toggledParam'));
+      }
+    },
+
+    sendControlAction: function (action) {
+      this.set('controlAction', action);
+      this.sendAction('controlAction', this.get('heading'), this.get('toggledParam'));
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/column-filter-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/column-filter-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/column-filter-widget.js
new file mode 100644
index 0000000..461dabe
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/column-filter-widget.js
@@ -0,0 +1,56 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  tagName: 'column-filter',
+
+  didInsertElement: function () {
+    if (this.get('filterValue')) {
+      this.send('sendFilter');
+    }
+  },
+
+  isSorted: (function () {
+    var sortProperties = this.get('sortProperties');
+
+    if (sortProperties) {
+      return sortProperties[0] === this.get('column.property');
+    } else {
+      return false;
+    }
+  }).property('sortProperties'),
+
+  actions: {
+    sendSort: function () {
+      this.sendAction('columnSorted', this.get('column.property'));
+    },
+
+    sendFilter: function (params) {
+      if (params && (params.from || params.from === 0) && (params.to || params.to === 0)) {
+        this.set('filterValue', Ember.Object.create({
+          min: params.from,
+          max: params.to
+        }));
+      }
+
+      this.sendAction('columnFiltered', this.get('column.property'), this.get('filterValue'));
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/date-range-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/date-range-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/date-range-widget.js
new file mode 100644
index 0000000..9e38786
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/date-range-widget.js
@@ -0,0 +1,85 @@
+/**
+ * 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.
+ */
+
+ /* globals moment */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  displayFromDate: function () {
+    return moment(this.get('dateRange.from')).format('MM/DD/YYYY');
+  }.property('dateRange.from'),
+
+  displayToDate: function () {
+    return moment(this.get('dateRange.to')).format('MM/DD/YYYY');
+  }.property('dateRange.to'),
+
+  updateMinDate: function () {
+    if (this.get('rendered')) {
+      this.$('.toDate').datepicker("option", "minDate", new Date(this.get('dateRange.from')));
+    }
+  }.observes('dateRange.from'),
+
+  updateMaxDate: function () {
+    if (this.get('rendered')) {
+      this.$('.fromDate').datepicker("option", "maxDate", new Date(this.get('dateRange.to')));
+    }
+  }.observes('dateRange.to'),
+
+  didInsertElement: function () {
+    var self = this;
+    var dateRange = this.get('dateRange');
+
+    if (!dateRange.get('min') && !dateRange.get('max')) {
+      dateRange.set('max', new Date());
+    }
+
+    if (!dateRange.get('from') && !dateRange.get('to')) {
+      dateRange.set('from', dateRange.get('min'));
+      dateRange.set('to', dateRange.get('max'));
+    }
+
+    this.$(".fromDate").datepicker({
+      defaultDate: new Date(dateRange.get("from")),
+      maxDate: new Date(dateRange.get('to')),
+
+      onSelect: function (selectedDate) {
+        self.$(".toDate").datepicker("option", "minDate", selectedDate);
+
+        dateRange.set('from', new Date(selectedDate).getTime());
+        self.sendAction('rangeChanged', dateRange);
+      }
+    });
+
+    this.$(".toDate").datepicker({
+      defaultDate: new Date(dateRange.get('to')),
+      minDate: new Date(dateRange.get('from')),
+
+      onSelect: function (selectedDate) {
+        selectedDate += ' 23:59';
+
+        self.$(".fromDate").datepicker("option", "maxDate", selectedDate);
+
+        dateRange.set('to', new Date(selectedDate).getTime());
+        self.sendAction('rangeChanged', dateRange);
+      }
+    });
+
+    this.set('rendered', true);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/expander-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/expander-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/expander-widget.js
new file mode 100644
index 0000000..12da9ea
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/expander-widget.js
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  tagName: 'expander',
+
+  didInsertElement: function () {
+    if (this.get('isExpanded')) {
+      this.$('.accordion-body').toggle();
+    }
+  },
+
+  actions: {
+    toggle: function () {
+      this.toggleProperty('isExpanded');
+      this.$('.accordion-body').toggle(200);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/extended-input.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/extended-input.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/extended-input.js
new file mode 100644
index 0000000..9b30201
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/extended-input.js
@@ -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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.TextField.extend(Ember.I18n.TranslateableProperties, {
+  didInsertElement: function () {
+    var dynamicValue = this.get('dynamicValue');
+    var dynamicContext = this.get('dynamicContext');
+
+    if (dynamicValue && dynamicContext) {
+      this.set('value', dynamicContext.get(dynamicValue));
+    }
+  },
+
+  sendValueChanged: function () {
+    var dynamicValue = this.get('dynamicValue');
+    var dynamicContext = this.get('dynamicContext');
+
+    if (dynamicValue && dynamicContext) {
+      dynamicContext.set(dynamicValue, this.get('value'));
+    }
+
+    this.sendAction('valueChanged', this.get('value'));
+  },
+
+  keyUp: function (e) {
+    //if user has pressed enter
+    if (e.keyCode === 13) {
+      this.sendAction('valueSearched', this.get('value'));
+    } else {
+      Ember.run.debounce(this, this.get('sendValueChanged'), 300);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/file-upload.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/file-upload.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/file-upload.js
new file mode 100644
index 0000000..1cd05ae
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/file-upload.js
@@ -0,0 +1,25 @@
+/**
+ * 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.
+ */
+
+import EmberUploader from 'ember-uploader';
+
+export default EmberUploader.FileField.extend({
+  filesDidChange: function(files) {
+    this.sendAction('filesUploaded',files); // sends this action to controller.
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/input-header.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/input-header.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/input-header.js
new file mode 100644
index 0000000..7ff5bf7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/input-header.js
@@ -0,0 +1,61 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  tagName: '',
+  dataTypes: null,
+  column: null,
+  precisionChanged: Ember.observer('column.precision', function () {
+    var col = this.get('column');
+    if( typeof col.precision !== 'number') {
+        Ember.set(col, 'precision', Number(col.precision));
+      }
+  }),
+
+  scaleChanged: Ember.observer('column.scale', function () {
+    var col = this.get('column');
+    if( typeof col.scale !== 'number'){
+      Ember.set(col,'scale',Number(col.scale));
+    }
+  }),
+
+  typeChanged: Ember.observer('column.type', function () {
+    var col = this.get('column');
+
+    var type = col.type;
+    if( type != "DECIMAL" ){
+      Ember.set(col,'scale');
+    }
+
+    if(type != "VARCHAR" && type != "CHAR" && type != "DECIMAL" ){
+      Ember.set(col,'precision');
+    }
+  }),
+
+  noPrecision: Ember.computed('column.type', function () {
+    var type = this.get('column').type;
+    return (type == "VARCHAR" || type == "CHAR" || type == "DECIMAL" ) ? false : true;
+  }),
+
+  noScale: Ember.computed('column.type', function () {
+    return this.get('column').type == "DECIMAL" ? false : true;
+  })
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/job-tr-view.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/job-tr-view.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/job-tr-view.js
new file mode 100644
index 0000000..f439ca2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/job-tr-view.js
@@ -0,0 +1,41 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+import utils from 'hive/utils/functions';
+
+export default Ember.Component.extend({
+  tagName: '',
+
+  canStop: function () {
+    return utils.insensitiveCompare(this.get('job.status'), constants.statuses.running, constants.statuses.initialized, constants.statuses.pending);
+  }.property('job.status'),
+
+  actions: {
+    requestFile: function () {
+      this.toggleProperty('expanded');
+
+      this.sendAction('onFileRequested', this.get('job'));
+    },
+
+    stopJob: function () {
+      this.sendAction('onStopJob', this.get('job'));
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/modal-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/modal-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/modal-widget.js
new file mode 100644
index 0000000..ce25bf1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/modal-widget.js
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend(Ember.I18n.TranslateableProperties, {
+  show: function () {
+    var self = this;
+
+    this.$('.modal').modal().on('hidden.bs.modal', function () {
+      self.sendAction('close');
+    });
+  }.on('didInsertElement'),
+
+  keyPress: function (e) {
+    Ember.run.debounce(this, function () {
+      if (e.which === 13) {
+        this.send('ok');
+      } else if (e.which === 27) {
+        this.send('close');
+      }
+    }, 200);
+  },
+
+  setupEvents: function () {
+    this.$(document).on('keyup', Ember.$.proxy(this.keyPress, this));
+  }.on('didInsertElement'),
+
+  destroyEvents: function () {
+    this.$(document).off('keyup', Ember.$.proxy(this.keyPress, this));
+  }.on('willDestroyElement'),
+
+  actions: {
+    ok: function () {
+      this.$('.modal').modal('hide');
+      this.sendAction('ok');
+    },
+    close: function () {
+      this.$('.modal').modal('hide');
+      this.sendAction('close');
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/navbar-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/navbar-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/navbar-widget.js
new file mode 100644
index 0000000..11333d0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/navbar-widget.js
@@ -0,0 +1,42 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Component.extend({
+  tagName: 'navigation-bar',
+  title: constants.appTitle,
+
+  items: Ember.A([
+    Ember.Object.create({text: 'menus.query',
+                         path: constants.namingConventions.routes.index}),
+
+    Ember.Object.create({text: 'menus.savedQueries',
+                         path: constants.namingConventions.routes.queries}),
+
+    Ember.Object.create({text: 'menus.history',
+                         path: constants.namingConventions.routes.history}),
+
+    Ember.Object.create({text: 'menus.udfs',
+                         path: constants.namingConventions.routes.udfs}),
+
+    Ember.Object.create({text: 'menus.uploadTable',
+      path: constants.namingConventions.routes.uploadTable})
+  ])
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/no-bubbling.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/no-bubbling.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/no-bubbling.js
new file mode 100644
index 0000000..4b723b1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/no-bubbling.js
@@ -0,0 +1,31 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  didInsertElement: function () {
+    var self = this;
+
+    this.$().click(function (e) {
+      e.stopPropagation();
+
+      self.sendAction('click', self.get('data'));
+    });
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/notify-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/notify-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/notify-widget.js
new file mode 100644
index 0000000..ba0f080
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/notify-widget.js
@@ -0,0 +1,31 @@
+/**
+* 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.
+*/
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  tagName: 'notifications',
+  classNames: [ 'notifications-container' ],
+  removeNotificationAction: 'removeNotification',
+
+  actions: {
+    removeNotification: function (notification) {
+      this.sendAction('removeNotificationAction', notification);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/number-range-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/number-range-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/number-range-widget.js
new file mode 100644
index 0000000..5d62b59
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/number-range-widget.js
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     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.
+ */
+
+import Ember from 'ember';
+import utils from 'hive/utils/functions';
+
+export default Ember.Component.extend({
+  didInsertElement: function () {
+    var self = this;
+    var numberRange = this.get('numberRange');
+
+    if (!numberRange.get('from') && !numberRange.get('to')) {
+      numberRange.set('from', numberRange.get('min'));
+      numberRange.set('to', numberRange.get('max'));
+    }
+
+    this.$('.slider').slider({
+      range: true,
+      min: numberRange.get('min'),
+      max: numberRange.get('max'),
+      units: numberRange.get('units'),
+      values: [numberRange.get('from'), numberRange.get('to')],
+
+      slide: function (event, ui) {
+        numberRange.set('from', ui.values[0]);
+        numberRange.set('to', ui.values[1]);
+        self.updateRangeLables();
+      },
+
+      change: function () {
+        self.sendAction('rangeChanged', numberRange);
+      }
+    });
+    this.updateRangeLables();
+    this.set('rendered', true);
+  },
+  updateRangeLables: function () {
+    var numberRange = this.get('numberRange');
+    numberRange.set('fromDuration', utils.secondsToHHMMSS(numberRange.get('from')));
+    numberRange.set('toDuration', utils.secondsToHHMMSS(numberRange.get('to')));
+  },
+  updateMin: function () {
+    if (this.get('rendered')) {
+      this.$('.slider').slider('values', 0, this.get('numberRange.from'));
+      this.updateRangeLables();
+    }
+  }.observes('numberRange.from'),
+
+  updateMax: function () {
+    if (this.get('rendered')) {
+      this.$('.slider').slider('values', 1, this.get('numberRange.to'));
+      this.updateRangeLables();
+    }
+  }.observes('numberRange.to')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/panel-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/panel-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/panel-widget.js
new file mode 100644
index 0000000..e2b4ae8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/panel-widget.js
@@ -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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend(Ember.I18n.TranslateableProperties, {
+  tagName: 'panel',
+
+  actions: {
+    sendMenuItemAction: function (action) {
+      this.set('menuItemAction', action);
+      this.sendAction('menuItemAction');
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/popover-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/popover-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/popover-widget.js
new file mode 100644
index 0000000..cfb0c31
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/popover-widget.js
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend(Ember.I18n.TranslateableProperties, {
+  tagName: 'popover',
+  attributeBindings: [ 'title', 'content:data-content' ],
+
+  didInsertElement: function () {
+    this.$().popover({
+      html: true,
+      placement: 'left',
+      trigger: 'hover'
+    });
+
+    this.$().attr('data-content', this.$('.hide').html());
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/progress-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/progress-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/progress-widget.js
new file mode 100644
index 0000000..9a459c3
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/progress-widget.js
@@ -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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  tagName: 'progress-bar',
+
+  updateValue: function () {
+    var progress = this.get('value') ? this.get('value').toFixed() : 0;
+
+    this.set('style', 'width: %@%'.fmt(progress));
+    this.set('percentage', '%@%'.fmt(progress));
+  }.observes('value').on('didInsertElement')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/query-editor.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/query-editor.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/query-editor.js
new file mode 100644
index 0000000..34b293c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/query-editor.js
@@ -0,0 +1,129 @@
+/**
+ * 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.
+ */
+
+/* global CodeMirror */
+
+/**
+/* Copyright (C) 2014 by Marijn Haverbeke <ma...@gmail.com> and others
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shal l be included in
+ * all copies or substantial portions of the Software.
+*/
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  tagName: 'query-editor',
+
+  tablesChanged: function () {
+    //Format hintOptions object as needed by the CodeMirror
+    //http://stackoverflow.com/questions/20023381/codemirror-how-add-tables-to-sql-hint
+    this.set('editor.options.hintOptions', { tables: this.get('tables') });
+  }.observes('tables'),
+
+  getColumnsHint: function (cm, tableName) {
+    var callback = function () {
+      CodeMirror.showHint(cm);
+    };
+
+    this.sendAction('columnsNeeded', tableName, callback);
+  },
+
+  initEditor: function () {
+    var editor,
+        updateSize,
+        self = this;
+
+    updateSize = function () {
+      editor.setSize(self.$(this).width(), self.$(this).height());
+      editor.refresh();
+    };
+
+    this.set('editor', CodeMirror.fromTextArea(document.getElementById('code-mirror'), {
+      mode: 'text/x-hive',
+      hint: CodeMirror.hint.sql,
+      indentWithTabs: true,
+      smartIndent: true,
+      lineNumbers: true,
+      matchBrackets : true,
+      autofocus: true,
+      extraKeys: {'Ctrl-Space': 'autocomplete'}
+    }));
+
+    CodeMirror.commands.autocomplete = function (cm) {
+      var lastWord = cm.getValue().split(' ').pop();
+
+      //if user wants to fill in a column
+      if (lastWord.indexOf('.') > -1) {
+        lastWord = lastWord.split('.')[0];
+
+        self.getColumnsHint(cm, lastWord);
+      } else {
+        CodeMirror.showHint(cm);
+      }
+    };
+
+    editor = this.get('editor');
+
+    editor.on('cursorActivity', function () {
+      self.set('highlightedText', editor.getSelections());
+    });
+
+    editor.setValue(this.get('query') || '');
+
+    editor.on('change', function (instance) {
+      Ember.run(function () {
+        self.set('query', instance.getValue());
+      });
+    });
+
+    this.$('.CodeMirror').resizable({
+      handles: 's',
+
+      resize: function () {
+        Ember.run.debounce(this, updateSize, 150);
+      }
+    }).find('.ui-resizable-s').addClass('grip fa fa-reorder');
+
+    this.tablesChanged();
+  }.on('didInsertElement'),
+
+  updateValue: function () {
+    var query = this.get('query');
+    var editor = this.get('editor');
+
+    var isFinalExplainQuery = (query.toUpperCase().trim().indexOf('EXPLAIN') > -1);
+    var editorQuery = editor.getValue();
+
+    if (editor.getValue() !== query) {
+      if(isFinalExplainQuery){
+        editor.setValue(editorQuery || '')
+      }else {
+        editor.setValue(query || '');
+      }
+    }
+
+  }.observes('query')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/radio-button.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/radio-button.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/radio-button.js
new file mode 100644
index 0000000..a07caaf
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/radio-button.js
@@ -0,0 +1,39 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  tagName: 'input',
+  type: 'radio',
+  attributeBindings: ['type', 'htmlChecked:checked', 'value', 'name', 'disabled'],
+
+  htmlChecked: function() {
+    return this.get('value') === this.get('checked');
+  }.property('value', 'checked'),
+
+  change: function() {
+    this.set('checked', this.get('value'));
+  },
+
+  _updateElementValue: function() {
+    Ember.run.next(this, function() {
+      this.$().prop('checked', this.get('htmlChecked'));
+    });
+  }.observes('htmlChecked')
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/select-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/select-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/select-widget.js
new file mode 100644
index 0000000..8bd7a22
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/select-widget.js
@@ -0,0 +1,66 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend(Ember.I18n.TranslateableProperties, {
+  tagName: 'dropdown',
+
+  selectedLabel: function () {
+    var value;
+
+    //if there's an item selected, retrieve the property to be displayed as a label
+    if (this.get('selectedValue') && this.get('labelPath')) {
+      value = this.get('selectedValue').get(this.get('labelPath'));
+
+      if (value) {
+        return value;
+      }
+    }
+
+    //else if a default label has been provided, use it as the selected label.
+    if (this.get('defaultLabel')) {
+      return this.get('defaultLabel');
+    }
+  }.property('selectedValue'),
+
+  didInsertElement: function () {
+    //if no selected item nor defaultLabel, set the selected value
+    if (!this.get('selectedValue') && !this.get('defaultLabel') && this.get('items')) {
+      this.set('selectedValue', this.get('items').objectAt(0));
+    }
+  },
+
+  actions: {
+    select: function (item){
+      this.set('selectedValue', item);
+    },
+
+    add: function () {
+      this.sendAction('itemAdded');
+    },
+
+    edit: function (item) {
+      this.sendAction('itemEdited', item);
+    },
+
+    remove: function (item) {
+      this.sendAction('itemRemoved', item);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/tabs-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/tabs-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/tabs-widget.js
new file mode 100644
index 0000000..abb1337
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/tabs-widget.js
@@ -0,0 +1,68 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  tagName: 'tabs',
+
+  didInsertElement: function () {
+    var tabToActivate,
+        tabs = this.get('tabs');
+
+    if (tabs.get('length')) {
+      tabToActivate = tabs.find(function (tab) {
+        return tab.get('active');
+      });
+
+      if (tabToActivate) {
+        this.set('selectedTab', tabToActivate);
+      } else {
+        this.set('selectedTab', tabs.objectAt(0));
+      }
+    }
+  },
+
+  activateTab: function () {
+    var selectedTab = this.get('selectedTab');
+
+    selectedTab.set('active', true);
+
+    this.get('tabs').without(selectedTab).forEach(function (tab) {
+      tab.set('active', false);
+    });
+  }.observes('selectedTab'),
+
+  removeEnabled: function () {
+    return this.get('canRemove') && this.get('tabs.length') > 1;
+  }.property('tabs.@each'),
+
+  actions: {
+    remove: function (tab) {
+      this.sendAction('removeClicked', tab);
+    },
+
+    selectTab: function (tab) {
+      this.set('selectedTab', tab);
+    },
+
+    titleClick: function(tab) {
+      this.sendAction('onActiveTitleClick', tab);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/tree-view.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/tree-view.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/tree-view.js
new file mode 100644
index 0000000..cd63f52
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/tree-view.js
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  tagName: 'tree-view'
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/typeahead-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/typeahead-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/typeahead-widget.js
new file mode 100644
index 0000000..5bc0bda
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/typeahead-widget.js
@@ -0,0 +1,108 @@
+/**
+ * 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.
+ */
+
+import Typeahead from 'ember-cli-selectize/components/ember-selectize';
+import Ember from 'ember';
+
+export default Typeahead.extend(Ember.I18n.TranslateableProperties, {
+  didInsertElement: function () {
+    this._super();
+
+    if (!this.get('selection') && this.get('content.firstObject')) {
+      this.set('selection', this.get('content.firstObject'));
+    }
+
+    this.selectize.on('dropdown_close', Ember.$.proxy(this.onClose, this));
+
+    if($('.selectize-input')) {$('.selectize-input').addClass( "mozBoxSizeFix" );}
+
+    var currentKeyName = this.get('safeValue');
+    var currentTypehead = $('*[keyname="' + currentKeyName +'"]');
+
+    if (currentTypehead.find($('.selectize-input')).has('.item').length == 0) {
+      currentTypehead.find($('.selectize-input')).addClass("has-options has-items ");
+
+      currentTypehead.find($('.selectized option:selected')).val(currentKeyName);
+      currentTypehead.find($('.selectized option:selected')).text(currentKeyName);
+
+      currentTypehead.find($('.selectize-input input')).css({'opacity': 0 , 'position': 'absolute' , 'left': '-10000px'});
+
+      var itemHtml = '<div data-value=' + currentKeyName + ' class=item >' + currentKeyName + '</div>';
+      currentTypehead.find($('.selectize-input')).append( itemHtml );
+
+    }
+  },
+
+  removeExcludedObserver: function () {
+    var options = this.get('content');
+
+    if (!options) {
+      options = this.removeExcluded(true);
+      this.set('content', options);
+    } else {
+      this.removeExcluded();
+    }
+  }.observes('excluded.@each.key').on('init'),
+
+  removeExcluded: function (shouldReturn) {
+    var excluded        = this.get('excluded') || [];
+    var options         = this.get('options');
+    var selection       = this.get('selection');
+    var objectToModify  = this.get('content');
+    var objectsToRemove = [];
+    var objectsToAdd    = [];
+
+    if (!options) {
+      return;
+    }
+
+    if (shouldReturn) {
+      objectToModify = Ember.copy(options);
+    }
+
+    var valuePath = this.get('optionValuePath');
+    var selectionName = selection ? selection[valuePath] : selection;
+
+    if (options) {
+      options.forEach(function (option) {
+        if (excluded.contains(option) && option.name !== selectionName) {
+          objectsToRemove.push(option);
+        } else if (!objectToModify.contains(option)) {
+          objectsToAdd.push(option);
+        }
+      });
+    }
+
+    objectToModify.removeObjects(objectsToRemove);
+    objectToModify.pushObjects(objectsToAdd);
+
+    return objectToModify;
+  },
+
+  onClose: function () {
+    if (!this.get('selection') && this.get('prevSelection')) {
+      this.set('selection', this.get('prevSelection'));
+    }
+  },
+
+  _onItemAdd: function (value) {
+    this._super(value);
+
+    this.set('prevSelection', this.get('selection'));
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/udf-tr-view.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/udf-tr-view.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/udf-tr-view.js
new file mode 100644
index 0000000..f019578
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/udf-tr-view.js
@@ -0,0 +1,81 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Component.extend({
+  tagName: 'tr',
+
+  didInsertElement: function () {
+    this._super();
+
+    if (this.get('udf.isNew')) {
+      this.set('udf.isEditing', true);
+    }
+  },
+
+  setfileBackup: function () {
+    if (!this.get('udf.isDirty')) {
+      this.set('fileBackup', this.get('udf.fileResource'));
+    }
+  }.observes('udf.isDirty').on('didInsertElement'),
+
+  actions: {
+    editUdf: function () {
+      this.set('udf.isEditing', true);
+    },
+
+    deleteUdf: function () {
+      this.sendAction('onDeleteUdf', this.get('udf'));
+    },
+
+    addFileResource: function () {
+      this.sendAction('onAddFileResource', this.get('udf'));
+    },
+
+    editFileResource: function (file) {
+      this.set('udf.fileResource', file);
+      this.set('udf.isEditingResource', true);
+    },
+
+    deleteFileResource: function (file) {
+      this.sendAction('onDeleteFileResource', file);
+    },
+
+    save: function () {
+      this.sendAction('onSaveUdf', this.get('udf'));
+    },
+
+    cancel: function () {
+      var self = this;
+
+      this.set('udf.isEditing', false);
+      this.set('udf.isEditingResource', false);
+
+      this.udf.get('fileResource').then(function (file) {
+        if (file) {
+          file.rollback();
+        }
+
+        self.udf.rollback();
+        self.udf.set('fileResource', self.get('fileBackup'));
+      });
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/visualization-tabs-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/visualization-tabs-widget.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/visualization-tabs-widget.js
new file mode 100644
index 0000000..4980b7a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/components/visualization-tabs-widget.js
@@ -0,0 +1,56 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+  tagName: 'tabs',
+
+  didInsertElement: function () {
+    var tabToActivate,
+        tabs = this.get('tabs');
+
+    if (tabs.get('length')) {
+      tabToActivate = tabs.find(function (tab) {
+        return tab.get('active');
+      });
+
+      if (tabToActivate) {
+        this.set('selectedTab', tabToActivate);
+      } else {
+        this.set('selectedTab', tabs.objectAt(0));
+      }
+    }
+  },
+
+  activateTab: function () {
+    var selectedTab = this.get('selectedTab');
+
+    selectedTab.set('active', true);
+
+    this.get('tabs').without(selectedTab).forEach(function (tab) {
+      tab.set('active', false);
+    });
+  }.observes('selectedTab'),
+
+  actions: {
+    selectTab: function (tab) {
+      this.set('selectedTab', tab);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/application.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/application.js
new file mode 100644
index 0000000..9a01d53
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/application.js
@@ -0,0 +1,26 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+
+  notifications: Ember.computed.alias('notifyService.notifications'),
+});
\ No newline at end of file


[31/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/api/util/ApiVersion.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/util/ApiVersion.java b/ambari-server/src/main/java/org/apache/ambari/server/api/util/ApiVersion.java
new file mode 100644
index 0000000..5e85e56
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/util/ApiVersion.java
@@ -0,0 +1,31 @@
+/**
+ * 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.ambari.server.api.util;
+
+import java.util.EnumSet;
+
+public enum ApiVersion {
+  v1,
+  v2;
+
+  public static EnumSet<ApiVersion> all = EnumSet.allOf(ApiVersion.class);
+  public static EnumSet<ApiVersion> v1Only = EnumSet.of(v1);
+  public static EnumSet<ApiVersion> v2Only = EnumSet.of(v2);
+  public static EnumSet<ApiVersion> v2Plus = EnumSet.complementOf(v1Only);
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index f5e8f39..cecbf50 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -189,6 +189,9 @@ public class Configuration {
   public static final String LDAP_GROUP_NAMING_ATTR_KEY = "authentication.ldap.groupNamingAttr";
   public static final String LDAP_GROUP_MEMEBERSHIP_ATTR_KEY = "authentication.ldap.groupMembershipAttr";
   public static final String LDAP_ADMIN_GROUP_MAPPING_RULES_KEY = "authorization.ldap.adminGroupMappingRules";
+  public static final String YARN_DASH_API_ENDPOINT = "yarn.dash.api.endpoint";
+  public static final String YARN_DASH_API_ENDPOINT_DEFAULT = "http://cn008.l42scl.hortonworks.com:9191/services/v1/applications";
+
   /**
    * When authentication through LDAP is enabled then Ambari Server uses this filter to lookup
    * the user in LDAP based on the provided ambari user name.
@@ -3030,4 +3033,8 @@ public class Configuration {
   public boolean isLdapAlternateUserSearchEnabled() {
     return Boolean.parseBoolean(properties.getProperty(LDAP_ALT_USER_SEARCH_ENABLED_KEY, LDAP_ALT_USER_SEARCH_ENABLED_DEFAULT));
   }
+
+  public String getDashApiEndpoint() {
+    return properties.getProperty(YARN_DASH_API_ENDPOINT, YARN_DASH_API_ENDPOINT_DEFAULT);
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
index b60592d..6c166dc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java
@@ -1234,7 +1234,7 @@ public class AmbariCustomCommandExecutionHelper {
 
       StackInfo stack = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion());
       if (stack != null) {
-        ServiceInfo serviceInfo = stack.getService(serviceName);
+        ServiceInfo serviceInfo = ambariMetaInfo.getService(stackId.getStackName(), stackId.getStackVersion(), serviceName);
 
         if (serviceInfo != null) {
           // if there is a chance that this action was triggered by a change in rack info then we want to

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
index d6b9d0e..4917d4f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
@@ -30,6 +30,7 @@ import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.internal.RequestStageContainer;
 import org.apache.ambari.server.controller.metrics.timeline.cache.TimelineMetricCacheProvider;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCacheProvider;
 import org.apache.ambari.server.metadata.RoleCommandOrder;
 import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
 import org.apache.ambari.server.security.authorization.AuthorizationException;
@@ -48,6 +49,8 @@ import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentFactory;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceFactory;
+import org.apache.ambari.server.state.ServiceGroup;
+import org.apache.ambari.server.state.ServiceGroupFactory;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.ServiceOsSpecific;
 import org.apache.ambari.server.state.State;
@@ -506,6 +509,13 @@ public interface AmbariManagementController {
   ServiceFactory getServiceFactory();
 
   /**
+   * Get the service groups factory for this management controller.
+   *
+   * @return the service factory
+   */
+  ServiceGroupFactory getServiceGroupFactory();
+
+  /**
    * Get the service component factory for this management controller.
    *
    * @return the service component factory
@@ -600,6 +610,24 @@ public interface AmbariManagementController {
                              Collection<ServiceComponentHost> ignoredHosts,
                              boolean runSmokeTest, boolean reconfigureClients) throws AmbariException;
 
+
+  /**
+   * Add stages for a service group to the request.
+   *
+   * @param requestStages       Stages currently associated with request
+   * @param cluster             cluster being acted on
+   * @param requestProperties   the request properties
+   * @param requestParameters   the request parameters; may be null
+   * @param changedServiceGroups     the service groups being changed
+   *
+   * @return request stages
+   *
+   * @throws AmbariException if stages can't be created
+   */
+  RequestStageContainer addServiceGroupStages(RequestStageContainer requestStages, Cluster cluster, Map<String, String> requestProperties,
+                                  Map<String, String> requestParameters,
+                                  Map<State, List<ServiceGroup>> changedServiceGroups) throws AmbariException;
+
   /**
    * Getter for the url of JDK, stored at server resources folder
    */
@@ -708,6 +736,8 @@ public interface AmbariManagementController {
    */
   RoleCommandOrder getRoleCommandOrder(Cluster cluster);
 
+  String getDashApiEndpoint();
+
   /**
    * Performs a test if LDAP server is reachable.
    *
@@ -796,6 +826,8 @@ public interface AmbariManagementController {
 
   TimelineMetricCacheProvider getTimelineMetricCacheProvider();
 
+  public ServiceGroupCacheProvider getServiceGroupCacheProvider();
+
   /**
    * Returns KerberosHelper instance
    * @return

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index dd3d098..ed10c3c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -44,8 +44,11 @@ import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
+import java.io.InputStream;
 import java.lang.reflect.Type;
 import java.net.InetAddress;
+import java.net.URL;
+import java.net.HttpURLConnection;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -65,18 +68,8 @@ import java.util.TreeMap;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
 
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.ClusterNotFoundException;
-import org.apache.ambari.server.DuplicateResourceException;
-import org.apache.ambari.server.HostNotFoundException;
-import org.apache.ambari.server.ObjectNotFoundException;
-import org.apache.ambari.server.ParentObjectNotFoundException;
-import org.apache.ambari.server.Role;
-import org.apache.ambari.server.RoleCommand;
-import org.apache.ambari.server.ServiceComponentHostNotFoundException;
-import org.apache.ambari.server.ServiceComponentNotFoundException;
-import org.apache.ambari.server.ServiceNotFoundException;
-import org.apache.ambari.server.StackAccessException;
+import jline.internal.Log;
+import org.apache.ambari.server.*;
 import org.apache.ambari.server.actionmanager.ActionManager;
 import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.RequestFactory;
@@ -87,13 +80,12 @@ import org.apache.ambari.server.agent.ExecutionCommand.KeyNames;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.configuration.Configuration.DatabaseType;
-import org.apache.ambari.server.controller.internal.RequestOperationLevel;
-import org.apache.ambari.server.controller.internal.RequestResourceFilter;
-import org.apache.ambari.server.controller.internal.RequestStageContainer;
-import org.apache.ambari.server.controller.internal.URLStreamProvider;
-import org.apache.ambari.server.controller.internal.WidgetLayoutResourceProvider;
-import org.apache.ambari.server.controller.internal.WidgetResourceProvider;
+import org.apache.ambari.server.controller.internal.*;
 import org.apache.ambari.server.controller.metrics.timeline.cache.TimelineMetricCacheProvider;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCache;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCacheKey;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCacheProvider;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCacheValue;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.customactions.ActionDefinition;
 import org.apache.ambari.server.metadata.ActionMetadata;
@@ -127,6 +119,7 @@ import org.apache.ambari.server.security.ldap.LdapBatchDto;
 import org.apache.ambari.server.security.ldap.LdapSyncDto;
 import org.apache.ambari.server.serveraction.kerberos.KerberosInvalidConfigurationException;
 import org.apache.ambari.server.serveraction.kerberos.KerberosOperationException;
+import org.apache.ambari.server.serveraction.servicegroup.YarnServiceGroupServerAction;
 import org.apache.ambari.server.stageplanner.RoleGraph;
 import org.apache.ambari.server.stageplanner.RoleGraphFactory;
 import org.apache.ambari.server.state.Cluster;
@@ -154,6 +147,8 @@ import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceComponentHostEvent;
 import org.apache.ambari.server.state.ServiceComponentHostFactory;
 import org.apache.ambari.server.state.ServiceFactory;
+import org.apache.ambari.server.state.ServiceGroup;
+import org.apache.ambari.server.state.ServiceGroupFactory;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.ServiceOsSpecific;
 import org.apache.ambari.server.state.StackId;
@@ -165,12 +160,11 @@ import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
 import org.apache.ambari.server.state.stack.RepositoryXml;
 import org.apache.ambari.server.state.stack.WidgetLayout;
 import org.apache.ambari.server.state.stack.WidgetLayoutInfo;
-import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEvent;
-import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStartEvent;
-import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStopEvent;
-import org.apache.ambari.server.state.svccomphost.ServiceComponentHostUpgradeEvent;
+import org.apache.ambari.server.state.svccomphost.*;
+import org.apache.ambari.server.state.UpgradeState;
 import org.apache.ambari.server.utils.SecretReference;
 import org.apache.ambari.server.utils.StageUtils;
+import org.apache.ambari.server.utils.MapUtils;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
@@ -190,6 +184,8 @@ import com.google.inject.Injector;
 import com.google.inject.Singleton;
 import com.google.inject.persist.Transactional;
 
+import javax.annotation.OverridingMethodsMustInvokeSuper;
+
 @Singleton
 public class AmbariManagementControllerImpl implements AmbariManagementController {
 
@@ -218,6 +214,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   @Inject
   private ServiceFactory serviceFactory;
   @Inject
+  private ServiceGroupFactory serviceGroupFactory;
+  @Inject
   private ServiceComponentFactory serviceComponentFactory;
   @Inject
   private ServiceComponentHostFactory serviceComponentHostFactory;
@@ -266,6 +264,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
 
   private MaintenanceStateHelper maintenanceStateHelper;
 
+  private static Map<String, String> componentNameMappings = MapUtils.fillMap("/var/lib/ambari-server/resources/componentsMap.dat");
+
   /**
    * The KerberosHelper to help setup for enabling for disabling Kerberos
    */
@@ -281,6 +281,9 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   final private static int REPO_URL_CONNECT_TIMEOUT = 3000;
   final private static int REPO_URL_READ_TIMEOUT = 2000;
 
+  final private static int DASH_URL_CONNECT_TIMEOUT = 3000;
+  final private static int DASH_URL_READ_TIMEOUT = 2000;
+
   final private String jdkResourceUrl;
   final private String javaHome;
   final private String jdkName;
@@ -1121,7 +1124,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
           throw new ServiceComponentHostNotFoundException(
               cluster.getClusterName(), null, request.getComponentName(), request.getHostname());
         }
-        request.setServiceName(serviceName);
+//        request.setServiceName(serviceName);
       }
     }
 
@@ -1132,7 +1135,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
       services.addAll(cluster.getServices().values());
     }
 
-    Set<ServiceComponentHostResponse> response =
+    Set<ServiceComponentHostResponse> responses =
         new HashSet<ServiceComponentHostResponse>();
 
     boolean checkDesiredState = false;
@@ -1169,7 +1172,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     for (Service s : services) {
       // filter on component name if provided
       Set<ServiceComponent> components = new HashSet<ServiceComponent>();
-      if (request.getComponentName() != null) {
+      if (request.getComponentName() != null && request.getServiceName() != null) {
         components.add(s.getServiceComponent(request.getComponentName()));
       } else {
         components.addAll(s.getServiceComponents().values());
@@ -1187,105 +1190,170 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
         Map<String, ServiceComponentHost> serviceComponentHostMap =
           sc.getServiceComponentHosts();
 
-        if (request.getHostname() != null) {
-          try {
-            if (serviceComponentHostMap == null
-                || !serviceComponentHostMap.containsKey(request.getHostname())) {
-              throw new ServiceComponentHostNotFoundException(cluster.getClusterName(),
-                s.getName(), sc.getName(), request.getHostname());
-            }
+        ServiceGroup sg = null;
+        try {
+          sg = cluster.getServiceGroup(s.getServiceGroupName());
+        } catch (ServiceGroupNotFoundException e) {
+          sg = null;
+        }
 
-            ServiceComponentHost sch = serviceComponentHostMap.get(request.getHostname());
+        if(sg == null || sg.getServiceGroupType().equalsIgnoreCase("AMBARI")) {
+          if (request.getHostname() != null) {
+            try {
+              if (serviceComponentHostMap == null
+                  || !serviceComponentHostMap.containsKey(request.getHostname())) {
+                throw new ServiceComponentHostNotFoundException(cluster.getClusterName(),
+                    s.getName(), sc.getName(), request.getHostname());
+              }
 
-            if (null == sch) {
-              // It's possible that the host was deleted during the time that the request was generated.
-              continue;
-            }
+              ServiceComponentHost sch = serviceComponentHostMap.get(request.getHostname());
 
-            if (checkDesiredState && (desiredStateToCheck != sch.getDesiredState())) {
-              continue;
-            }
+              if (null == sch) {
+                // It's possible that the host was deleted during the time that the request was generated.
+                continue;
+              }
 
-            if (checkState && stateToCheck != sch.getState()) {
-              continue;
-            }
+              if (checkDesiredState && (desiredStateToCheck != sch.getDesiredState())) {
+                continue;
+              }
 
-            if (request.getAdminState() != null) {
-              String stringToMatch =
-                  sch.getComponentAdminState() == null ? "" : sch.getComponentAdminState().name();
-              if (!request.getAdminState().equals(stringToMatch)) {
+              if (checkState && stateToCheck != sch.getState()) {
                 continue;
               }
-            }
 
-            ServiceComponentHostResponse r = sch.convertToResponse();
-            if (null == r || (filterBasedConfigStaleness && r.isStaleConfig() != staleConfig)) {
-              continue;
-            }
+              if (request.getAdminState() != null) {
+                String stringToMatch =
+                    sch.getComponentAdminState() == null ? "" : sch.getComponentAdminState().name();
+                if (!request.getAdminState().equals(stringToMatch)) {
+                  continue;
+                }
+              }
 
-            Host host = hosts.get(sch.getHostName());
-            if (host == null) {
-              throw new HostNotFoundException(cluster.getClusterName(), sch.getHostName());
-            }
+              ServiceComponentHostResponse r = sch.convertToResponse();
+              if (null == r || (filterBasedConfigStaleness && r.isStaleConfig() != staleConfig)) {
+                continue;
+              }
 
-            r.setMaintenanceState(maintenanceStateHelper.getEffectiveState(sch, host).name());
-            response.add(r);
-          } catch (ServiceComponentHostNotFoundException e) {
-            if (request.getServiceName() == null || request.getComponentName() == null) {
-              // Ignore the exception if either the service name or component name are not specified.
-              // This is an artifact of how we get host_components and can happen in the case where
-              // we get all host_components for a host, for example.
-              LOG.debug("Ignoring not specified host_component ", e);
-
-            } else {
-              // Otherwise rethrow the exception and let the caller decide if it's an error condition.
-              // Logging the exception as debug since this does not necessarily indicate an error
-              // condition.
-              LOG.debug("ServiceComponentHost not found ", e);
-              throw new ServiceComponentHostNotFoundException(cluster.getClusterName(),
-                  request.getServiceName(), request.getComponentName(), request.getHostname());
-            }
-          }
-        } else {
-          for (ServiceComponentHost sch : serviceComponentHostMap.values()) {
-            if (null == sch) {
-              // It's possible that the host was deleted during the time that the request was generated.
-              continue;
-            }
+              Host host = hosts.get(sch.getHostName());
+              if (host == null) {
+                throw new HostNotFoundException(cluster.getClusterName(), sch.getHostName());
+              }
 
-            if (checkDesiredState && (desiredStateToCheck != sch.getDesiredState())) {
-              continue;
-            }
+              r.setMaintenanceState(maintenanceStateHelper.getEffectiveState(sch, host).name());
+              responses.add(r);
+            } catch (ServiceComponentHostNotFoundException e) {
+              if (request.getServiceName() == null || request.getComponentName() == null) {
+                // Ignore the exception if either the service name or component name are not specified.
+                // This is an artifact of how we get host_components and can happen in the case where
+                // we get all host_components for a host, for example.
+                LOG.debug("Ignoring not specified host_component ", e);
 
-            if (checkState && stateToCheck != sch.getState()) {
-              continue;
+              } else {
+                // Otherwise rethrow the exception and let the caller decide if it's an error condition.
+                // Logging the exception as debug since this does not necessarily indicate an error
+                // condition.
+                LOG.debug("ServiceComponentHost not found ", e);
+                throw new ServiceComponentHostNotFoundException(cluster.getClusterName(),
+                    request.getServiceName(), request.getComponentName(), request.getHostname());
+              }
             }
+          } else {
+            for (ServiceComponentHost sch : serviceComponentHostMap.values()) {
+              if (null == sch) {
+                // It's possible that the host was deleted during the time that the request was generated.
+                continue;
+              }
 
-            if (request.getAdminState() != null) {
-              String stringToMatch =
-                  sch.getComponentAdminState() == null ? "" : sch.getComponentAdminState().name();
-              if (!request.getAdminState().equals(stringToMatch)) {
+              if (checkDesiredState && (desiredStateToCheck != sch.getDesiredState())) {
                 continue;
               }
-            }
 
-            ServiceComponentHostResponse r = sch.convertToResponse();
-            if (null == r || (filterBasedConfigStaleness && r.isStaleConfig() != staleConfig)) {
-              continue;
-            }
+              if (checkState && stateToCheck != sch.getState()) {
+                continue;
+              }
+
+              if (request.getAdminState() != null) {
+                String stringToMatch =
+                    sch.getComponentAdminState() == null ? "" : sch.getComponentAdminState().name();
+                if (!request.getAdminState().equals(stringToMatch)) {
+                  continue;
+                }
+              }
+
+              ServiceComponentHostResponse r = sch.convertToResponse();
+              if (null == r || (filterBasedConfigStaleness && r.isStaleConfig() != staleConfig)) {
+                continue;
+              }
+
+              Host host = hosts.get(sch.getHostName());
+              if (host == null) {
+                throw new HostNotFoundException(cluster.getClusterName(), sch.getHostName());
+              }
 
-            Host host = hosts.get(sch.getHostName());
-            if (host == null) {
-              throw new HostNotFoundException(cluster.getClusterName(), sch.getHostName());
+              r.setMaintenanceState(maintenanceStateHelper.getEffectiveState(sch, host).name());
+              responses.add(r);
             }
+          }
+        } else {
+          ServiceGroupCache cache = getServiceGroupCacheProvider().getServiceGroupCache();
+          int desiredCount = sc.getDesiredCount();
+          String clusterName = sc.getClusterName();
+          String serviceName = sc.getServiceName();
+          String componentName = sc.getName();
+          String mappedComponentName = componentNameMappings.containsKey(componentName)?
+              componentNameMappings.get(componentName) : componentName;
+          String displayName = componentName;
+          HostComponentAdminState adminState = HostComponentAdminState.INSERVICE;
+          String stackVersion = "";
+          String desiredStackVersion = "";
+          String desiredState = sc.isClientComponent()? State.INSTALLED.toString(): State.STARTED.toString();
+          int totalCount = 0;
+
+          ServiceGroupCacheKey cacheKey = new ServiceGroupCacheKey(sg.getName());
+          Map<String, Object> responseMap = null;
+          try {
+            responseMap = cache.getResponseFromCache(cacheKey);
+          } catch (Exception e) {
+            Log.info("Hit exception when retrieving service group from cache. Exception: " + e.getMessage());
+          }
 
-            r.setMaintenanceState(maintenanceStateHelper.getEffectiveState(sch, host).name());
-            response.add(r);
+          if(responseMap != null && responseMap.containsKey("containers")) {
+            for(Map<String, String> cMap : (ArrayList<Map<String, String>>) responseMap.get("containers")) {
+              String dashContainerName = cMap.get("id");
+              String dashComponentName = cMap.get("component_name");
+              String dashState = cMap.get("state");
+              String dashHostName = cMap.get("hostname");
+              String dashBareHostName = cMap.get("bare_host");
+
+              if (dashComponentName.contains(mappedComponentName)) {
+                String liveState = State.INSTALLED.toString();
+                if(dashState.equalsIgnoreCase("READY")) {
+                  liveState = sc.isClientComponent()? State.INSTALLED.toString() : State.STARTED.toString();
+                }
+                ServiceComponentHostResponse r = new ServiceComponentHostResponse(clusterName, serviceName, componentName,
+                    displayName, dashHostName, liveState, stackVersion, desiredState, desiredStackVersion, adminState,
+                    dashBareHostName, dashContainerName);
+                r.setUpgradeState(UpgradeState.NONE);
+                r.setMaintenanceState(MaintenanceState.OFF.name());
+                responses.add(r);
+                totalCount++;
+              }
+            }
+          }
+          if(totalCount < desiredCount) {
+            while(totalCount < desiredCount) {
+              ServiceComponentHostResponse r = new ServiceComponentHostResponse(clusterName, serviceName, componentName,
+                  displayName, "", State.INIT.toString(), stackVersion, desiredState, desiredStackVersion, adminState);
+              r.setUpgradeState(UpgradeState.NONE);
+              r.setMaintenanceState(MaintenanceState.OFF.name());
+              responses.add(r);
+              totalCount++;
+            }
           }
         }
       }
     }
-    return response;
+    return responses;
   }
 
   @Override
@@ -2380,6 +2448,61 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     }
   }
 
+
+  private RequestStageContainer doStageCreationForServiceGroups(RequestStageContainer requestStages, Cluster cluster,
+      Map<State, List<ServiceGroup>> changedServiceGroups, Map<String, String> requestParameters,
+      Map<String, String> requestProperties)
+      throws AmbariException {
+
+    if (changedServiceGroups == null || changedServiceGroups.isEmpty()) {
+      LOG.debug("Created 0 stages");
+      return requestStages;
+    }
+
+    String clusterHostInfoJson = StageUtils.getGson().toJson(
+        StageUtils.getClusterHostInfo(cluster));
+    String hostParamsJson = StageUtils.getGson().toJson(
+        customCommandExecutionHelper.createDefaultHostParams(cluster));
+
+    Stage stage = createNewStage(requestStages.getLastStageId(), cluster,
+        requestStages.getId(), requestProperties.get(REQUEST_CONTEXT_PROPERTY),
+        clusterHostInfoJson, "{}", hostParamsJson);
+
+    String ambariServerHostname = StageUtils.getHostName();
+    ServiceComponentHostServerActionEvent event = new ServiceComponentHostServerActionEvent(
+        "AMBARI_SERVER",
+        ambariServerHostname, // TODO: Choose a random hostname from the cluster. All tasks for the AMBARI_SERVER service will be executed on this Ambari server
+        System.currentTimeMillis());
+
+    for(State newState : changedServiceGroups.keySet()) {
+      for(ServiceGroup sg : changedServiceGroups.get(newState)) {
+        Map<String, String> commandParameters = new HashMap<>();
+        commandParameters.put(YarnServiceGroupServerAction.COMMAND_PARAM_SERVICE_GROUP, sg.getName());
+        commandParameters.put(YarnServiceGroupServerAction.COMMAND_PARAM_DESIRED_STATE, newState.toString());
+        commandParameters.put(YarnServiceGroupServerAction.COMMAND_PARAM_DASH_API_ENDPOINT, getDashApiEndpoint());
+        String commandDetail = "";
+        if (newState == State.INSTALLED) {
+          if(sg.getDesiredState() == State.INIT) {
+            commandDetail = "Installing " + sg.getName();
+          } else if(sg.getDesiredState() == State.STARTED) {
+            commandDetail = "Stopping " + sg.getName();
+          }
+        } else if (newState == State.STARTED) {
+          commandDetail = "Starting " + sg.getName();
+        }
+        stage.addServerActionCommand(YarnServiceGroupServerAction.class.getName(), null, Role.AMBARI_SERVER_ACTION,
+            RoleCommand.EXECUTE, cluster.getClusterName(), event, commandParameters, commandDetail,
+            findConfigurationTagsWithOverrides(cluster, null), configs.getDefaultServerTaskTimeout(),
+            false, false);
+      }
+    }
+    RoleCommandOrder rco = getRoleCommandOrder(cluster);
+    RoleGraph rg = roleGraphFactory.createNew(rco);
+    rg.build(stage);
+    requestStages.addStages(rg.getStages());
+    return requestStages;
+  }
+
   private RequestStageContainer doStageCreation(RequestStageContainer requestStages,
       Cluster cluster,
       Map<State, List<Service>> changedServices,
@@ -2855,6 +2978,20 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     return response;  }
 
   @Transactional
+  void updateServiceGroupStates(
+      Cluster cluster,
+      Map<State, List<ServiceGroup>> changedServiceGroups) {
+    if (changedServiceGroups != null) {
+      for (Entry<State, List<ServiceGroup>> entry : changedServiceGroups.entrySet()) {
+        State newState = entry.getKey();
+        for (ServiceGroup sg : entry.getValue()) {
+          sg.setDesiredState(newState);
+        }
+      }
+    }
+  }
+
+  @Transactional
   void updateServiceStates(
       Cluster cluster,
       Map<State, List<Service>> changedServices,
@@ -2945,6 +3082,27 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     return requestStages;
   }
 
+  @Override
+  public RequestStageContainer addServiceGroupStages(RequestStageContainer requestStages, Cluster cluster,
+     Map<String, String> requestProperties, Map<String, String> requestParameters,
+     Map<State, List<ServiceGroup>> changedServiceGroups) throws AmbariException {
+
+    if (requestStages == null) {
+      requestStages = new RequestStageContainer(actionManager.getNextRequestId(), null, requestFactory, actionManager);
+    }
+
+    requestStages = doStageCreationForServiceGroups(requestStages, cluster, changedServiceGroups,
+        requestParameters, requestProperties);
+    Lock clusterWriteLock = cluster.getClusterGlobalLock().writeLock();
+    clusterWriteLock.lock();
+    try {
+      updateServiceGroupStates(cluster, changedServiceGroups);
+    } finally {
+      clusterWriteLock.unlock();
+    }
+    return requestStages;
+  }
+
   //todo: for now made this public since is is still used by createHostComponents
   //todo: delete after all host component logic is in HostComponentResourceProvider
   public void validateServiceComponentHostRequest(ServiceComponentHostRequest request) {
@@ -4397,6 +4555,11 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   }
 
   @Override
+  public ServiceGroupFactory getServiceGroupFactory() {
+    return serviceGroupFactory;
+  }
+
+  @Override
   public ServiceComponentFactory getServiceComponentFactory() {
     return serviceComponentFactory;
   }
@@ -4480,6 +4643,11 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   }
 
   @Override
+  public String getDashApiEndpoint() {
+    return configs.getDashApiEndpoint();
+  }
+
+  @Override
   public boolean checkLdapConfigured() {
     return ldapDataPopulator.isLdapEnabled();
   }
@@ -4548,7 +4716,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
       StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion());
       if (service != null) {
         // Service widgets
-        ServiceInfo serviceInfo = stackInfo.getService(service.getName());
+        ServiceInfo serviceInfo = stackInfo.getService(service.getStackServiceName());
         File widgetDescriptorFile = serviceInfo.getWidgetsDescriptorFile();
         if (widgetDescriptorFile != null && widgetDescriptorFile.exists()) {
           try {
@@ -4714,6 +4882,12 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   }
 
   @Override
+  public ServiceGroupCacheProvider getServiceGroupCacheProvider() {
+    return injector.getInstance(ServiceGroupCacheProvider.class);
+  }
+
+
+  @Override
   public KerberosHelper getKerberosHelper() {
     return kerberosHelper;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index db66961..e028593 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -371,12 +371,16 @@ public class AmbariServer {
       // requests.
       root.addFilter(new FilterHolder(injector.getInstance(AmbariViewsSecurityHeaderFilter.class)), "/api/v1/views/*",
           DISPATCHER_TYPES);
+      root.addFilter(new FilterHolder(injector.getInstance(AmbariViewsSecurityHeaderFilter.class)), "/api/v2/views/*",
+          DISPATCHER_TYPES);
 
       // since views share the REST API threadpool, a misbehaving view could
       // consume all of the available threads and effectively cause a loss of
       // service for Ambari
       root.addFilter(new FilterHolder(injector.getInstance(ViewThrottleFilter.class)),
           "/api/v1/views/*", DISPATCHER_TYPES);
+      root.addFilter(new FilterHolder(injector.getInstance(ViewThrottleFilter.class)),
+          "/api/v2/views/*", DISPATCHER_TYPES);
 
       // session-per-request strategy for api
       root.addFilter(new FilterHolder(injector.getInstance(AmbariPersistFilter.class)), "/api/*", DISPATCHER_TYPES);
@@ -387,6 +391,7 @@ public class AmbariServer {
 
       root.addFilter(new FilterHolder(springSecurityFilter), "/api/*", DISPATCHER_TYPES);
       root.addFilter(new FilterHolder(new UserNameOverrideFilter()), "/api/v1/users/*", DISPATCHER_TYPES);
+      root.addFilter(new FilterHolder(new UserNameOverrideFilter()), "/api/v2/users/*", DISPATCHER_TYPES);
 
       // session-per-request strategy for agents
       agentroot.addFilter(new FilterHolder(injector.getInstance(AmbariPersistFilter.class)), "/agent/*", DISPATCHER_TYPES);
@@ -485,7 +490,7 @@ public class AmbariServer {
           "org.apache.ambari.server.api");
 
       sh.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature", "true");
-      root.addServlet(sh, "/api/v1/*");
+      root.addServlet(sh, "/api/*");
       sh.setInitOrder(2);
 
       SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index 617553b..879c4c0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -69,9 +69,12 @@ import org.apache.ambari.server.controller.internal.KerberosDescriptorResourcePr
 import org.apache.ambari.server.controller.internal.MemberResourceProvider;
 import org.apache.ambari.server.controller.internal.RepositoryVersionResourceProvider;
 import org.apache.ambari.server.controller.internal.ServiceResourceProvider;
+import org.apache.ambari.server.controller.internal.ServiceGroupResourceProvider;
 import org.apache.ambari.server.controller.internal.UpgradeResourceProvider;
 import org.apache.ambari.server.controller.metrics.timeline.cache.TimelineMetricCacheEntryFactory;
 import org.apache.ambari.server.controller.metrics.timeline.cache.TimelineMetricCacheProvider;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCacheEntryFactory;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCacheProvider;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
 import org.apache.ambari.server.controller.utilities.KerberosChecker;
 import org.apache.ambari.server.notifications.DispatchFactory;
@@ -100,13 +103,16 @@ import org.apache.ambari.server.state.ConfigFactory;
 import org.apache.ambari.server.state.ConfigImpl;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceGroup;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentFactory;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceComponentHostFactory;
 import org.apache.ambari.server.state.ServiceComponentImpl;
 import org.apache.ambari.server.state.ServiceFactory;
+import org.apache.ambari.server.state.ServiceGroupFactory;
 import org.apache.ambari.server.state.ServiceImpl;
+import org.apache.ambari.server.state.ServiceGroupImpl;
 import org.apache.ambari.server.state.cluster.ClusterFactory;
 import org.apache.ambari.server.state.cluster.ClusterImpl;
 import org.apache.ambari.server.state.cluster.ClustersImpl;
@@ -361,6 +367,8 @@ public class ControllerModule extends AbstractModule {
     bind(ViewInstanceHandlerList.class).to(AmbariHandlerList.class);
     bind(TimelineMetricCacheProvider.class);
     bind(TimelineMetricCacheEntryFactory.class);
+    bind(ServiceGroupCacheProvider.class);
+    bind(ServiceGroupCacheEntryFactory.class);
     bind(SecurityConfigurationFactory.class).in(Scopes.SINGLETON);
 
     bind(PersistedState.class).to(PersistedStateImpl.class);
@@ -424,11 +432,14 @@ public class ControllerModule extends AbstractModule {
         Host.class, HostImpl.class).build(HostFactory.class));
     install(new FactoryModuleBuilder().implement(
         Service.class, ServiceImpl.class).build(ServiceFactory.class));
+    install(new FactoryModuleBuilder().implement(
+        ServiceGroup.class, ServiceGroupImpl.class).build(ServiceGroupFactory.class));
 
     install(new FactoryModuleBuilder()
         .implement(ResourceProvider.class, Names.named("host"), HostResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("hostComponent"), HostComponentResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("service"), ServiceResourceProvider.class)
+        .implement(ResourceProvider.class, Names.named("servicegroup"), ServiceGroupResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("component"), ComponentResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("member"), MemberResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("repositoryVersion"), RepositoryVersionResourceProvider.class)

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
index 3ec38c2..3f3f8ad 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
@@ -46,6 +46,11 @@ public interface ResourceProviderFactory {
       Map<Type, String> keyPropertyIds,
       AmbariManagementController managementController);
 
+  @Named("servicegroup")
+  ResourceProvider getServiceGroupResourceProvider(Set<String> propertyIds,
+      Map<Type, String> keyPropertyIds,
+      AmbariManagementController managementController);
+
   @Named("component")
   ResourceProvider getComponentResourceProvider(Set<String> propertyIds,
       Map<Type, String> keyPropertyIds,

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentHostResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentHostResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentHostResponse.java
index 85b2b46..7d7ef34 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentHostResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentHostResponse.java
@@ -31,6 +31,8 @@ public class ServiceComponentHostResponse {
   private String componentName;
   private String displayName;
   private String hostname;
+  private String baseHostName;
+  private String containerName;
   // type -> desired config
   private Map<String, HostConfig> actualConfigs;
   private String liveState;
@@ -48,6 +50,17 @@ public class ServiceComponentHostResponse {
                                       String liveState, String stackVersion,
                                       String desiredState, String desiredStackVersion,
                                       HostComponentAdminState adminState) {
+
+    this(clusterName, serviceName, componentName, displayName, hostname,
+        liveState, stackVersion, desiredState, desiredStackVersion, adminState, null, null);
+  }
+
+  public ServiceComponentHostResponse(String clusterName, String serviceName,
+                                      String componentName, String displayName, String hostname,
+                                      String liveState, String stackVersion,
+                                      String desiredState, String desiredStackVersion,
+                                      HostComponentAdminState adminState,
+                                      String bareHostName, String containerName) {
     this.clusterName = clusterName;
     this.serviceName = serviceName;
     this.componentName = componentName;
@@ -60,11 +73,13 @@ public class ServiceComponentHostResponse {
     if (adminState != null) {
       this.adminState = adminState.name();
     }
+    this.baseHostName = bareHostName;
+    this.containerName = containerName;
   }
 
-  /**
-   * @return the serviceName
-   */
+    /**
+     * @return the serviceName
+     */
   public String getServiceName() {
     return serviceName;
   }
@@ -98,6 +113,35 @@ public class ServiceComponentHostResponse {
   }
 
   /**
+   * @return the bare-metal hostname
+   */
+  public String getBareHostName() {
+    return baseHostName;
+  }
+
+  /**
+   * @param baseHostName the bare-metal hostname to set
+   */
+  public void setBareHostName(String baseHostName) {
+    this.baseHostName = baseHostName;
+  }
+
+  /**
+   * @return the container name
+   */
+  public String getContainerName() {
+    return containerName;
+  }
+
+  /**
+   * @param containerName the container name to set
+   */
+  public void setContainerName(String containerName) {
+    this.containerName = containerName;
+  }
+
+
+  /**
    * @return the hostname
    */
   public String getHostname() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentRequest.java
index ba0b84f..b1a6c5d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentRequest.java
@@ -29,29 +29,37 @@ public class ServiceComponentRequest {
 
   private String desiredState; // CREATE/UPDATE
 
+  private String desiredCount; // CREATE/UPDATE
+
   private String componentCategory;
 
   private String recoveryEnabled; // CREATE/UPDATE
 
   public ServiceComponentRequest(String clusterName, String serviceName,
                                  String componentName, String desiredState) {
-    this(clusterName, serviceName, componentName, desiredState, null, null);
+    this(clusterName, serviceName, componentName, desiredState, null, null, null);
+  }
+
+  public ServiceComponentRequest(String clusterName, String serviceName,
+                                 String componentName, String desiredState, String desiredCount) {
+    this(clusterName, serviceName, componentName, desiredState, desiredCount, null, null);
   }
 
   public ServiceComponentRequest(String clusterName, String serviceName,
-                                 String componentName, String desiredState,
+                                 String componentName, String desiredState, String desiredCount,
                                  String recoveryEnabled) {
-    this(clusterName, serviceName, componentName, desiredState, recoveryEnabled, null);
+    this(clusterName, serviceName, componentName, desiredState, desiredCount, recoveryEnabled, null);
   }
 
   public ServiceComponentRequest(String clusterName,
                                  String serviceName, String componentName,
-                                 String desiredState, String recoveryEnabled,
+                                 String desiredState, String desiredCount, String recoveryEnabled,
                                  String componentCategory) {
     this.clusterName = clusterName;
     this.serviceName = serviceName;
     this.componentName = componentName;
     this.desiredState = desiredState;
+    this.desiredCount = desiredCount;
     this.recoveryEnabled = recoveryEnabled;
     this.componentCategory = componentCategory;
   }
@@ -99,6 +107,20 @@ public class ServiceComponentRequest {
   }
 
   /**
+   * @return the desiredCount
+   */
+  public String getDesiredCount() {
+    return desiredCount;
+  }
+
+  /**
+   * @param desiredCount the desiredCount to set
+   */
+  public void setDesiredCount(String desiredCount) {
+    this.desiredCount = desiredCount;
+  }
+
+  /**
    * @return the clusterName
    */
   public String getClusterName() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentResponse.java
index cb84b89..fae09f4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceComponentResponse.java
@@ -43,6 +43,8 @@ public class ServiceComponentResponse {
 
   private int installedCount;
 
+  private int desiredCount;
+
   private boolean recoveryEnabled;
 
   public ServiceComponentResponse(Long clusterId, String clusterName,
@@ -53,6 +55,7 @@ public class ServiceComponentResponse {
                                   int totalCount,
                                   int startedCount,
                                   int installedCount,
+                                  int desiredCount,
                                   boolean recoveryEnabled,
                                   String displayName) {
     super();
@@ -66,6 +69,7 @@ public class ServiceComponentResponse {
     this.totalCount = totalCount;
     this.startedCount = startedCount;
     this.installedCount = installedCount;
+    this.desiredCount = desiredCount;
     this.recoveryEnabled = recoveryEnabled;
   }
 
@@ -161,6 +165,23 @@ public class ServiceComponentResponse {
   }
 
   /**
+   * Get the number of desired SCH's
+   * @return number of desired SCH's
+   */
+  public int getDesiredCount() {
+    return desiredCount;
+  }
+
+  /**
+   * Set the number of desired SCH's
+   * @param desiredCount
+   */
+  public void setDesiredCount(int desiredCount) {
+    this.desiredCount = desiredCount;
+  }
+
+
+  /**
    * Get the component category.
    *
    * @return the category

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupRequest.java
new file mode 100644
index 0000000..af00bb6
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupRequest.java
@@ -0,0 +1,152 @@
+/**
+ * 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.ambari.server.controller;
+
+
+
+public class ServiceGroupRequest {
+
+  private String clusterName; // REF
+  private String serviceGroupName; // GET/CREATE/UPDATE/DELETE
+  private String serviceGroupDisplayName; // GET/CREATE/UPDATE/DELETE
+  private String serviceGroupType; // GET/CREATE/UPDATE/DELETE
+  private String assemblyFile; // GET/CREATE/UPDATE/DELETE
+  private String desiredState;
+  private String currentState;
+
+  public ServiceGroupRequest(String clusterName, String serviceGroupName, String serviceGroupDisplayName,
+      String serviceGroupType, String assemblyFile, String desiredState, String currentState) {
+    this.clusterName = clusterName;
+    this.serviceGroupName = serviceGroupName;
+    this.serviceGroupDisplayName = serviceGroupDisplayName;
+    this.serviceGroupType = serviceGroupType;
+    this.assemblyFile = assemblyFile;
+    this.desiredState = desiredState;
+    this.currentState = currentState;
+  }
+
+  /**
+   * @return the clusterName
+   */
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  /**
+   * @param clusterName the clusterName to set
+   */
+  public void setClusterName(String clusterName) {
+    this.clusterName = clusterName;
+  }
+
+  /**
+   * @return the serviceGroupName
+   */
+  public String getServiceGroupName() {
+    return serviceGroupName;
+  }
+
+  /**
+   * @param serviceGroupName the service group name to set
+   */
+  public void setServiceGroupName(String serviceGroupName) {
+    this.serviceGroupName = serviceGroupName;
+  }
+
+  /**
+   * @return the serviceGroupDisplayName
+   */
+  public String getServiceGroupDisplayName() {
+    return serviceGroupDisplayName;
+  }
+
+  /**
+   * @param serviceGroupDisplayName the service group display name to set
+   */
+  public void setServiceGroupDisplayName(String serviceGroupDisplayName) {
+    this.serviceGroupDisplayName = serviceGroupDisplayName;
+  }
+
+  /**
+   * @return the desired state of the service group
+   */
+  public String getDesiredState() {
+    return desiredState;
+  }
+
+  /**
+   * @param desiredState the desired state of service group
+   */
+  public void setDesiredState(String desiredState) {
+    this.desiredState = desiredState;
+  }
+
+  /**
+   * @return the current state of the service group
+   */
+  public String getCurrentState() {
+    return currentState;
+  }
+
+  /**
+   * @param currentState the current state of service group
+   */
+  public void setCurrentState(String currentState) {
+    this.currentState = currentState;
+  }
+
+  /**
+   * @return the serviceGroupType
+   */
+  public String getServiceGroupType() {
+    return serviceGroupType;
+  }
+
+  /**
+   * @param serviceGroupType the service group type to set
+   */
+  public void setServiceGroupType(String serviceGroupType) {
+    this.serviceGroupType = serviceGroupType;
+  }
+
+  /**
+   * @return the assembly file
+   */
+  public String getAssemblyFile() {
+    return assemblyFile;
+  }
+
+  /**
+   * @param assemblyFile the assembly file to set
+   */
+  public void setAssemblyFile(String assemblyFile) {
+    this.assemblyFile = assemblyFile;
+  }
+
+
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("clusterName=" + clusterName
+        + ", serviceGroupName=" + serviceGroupName
+        + ", serviceGroupDisplayName=" + serviceGroupDisplayName
+        + ", serviceGroupType=" + serviceGroupType
+        + ", desiredState=" + desiredState
+        + ", assemblyFile=" + assemblyFile);
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupResponse.java
new file mode 100644
index 0000000..5451160
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupResponse.java
@@ -0,0 +1,239 @@
+/**
+ * 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.ambari.server.controller;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+
+public class ServiceGroupResponse {
+
+  private Long clusterId;
+  private String clusterName;
+  private String serviceGroupName;
+  private String serviceGroupDisplayName;
+  private String serviceGroupType;
+  private String assemblyFile;
+  private String desiredState;
+  private String currentState;
+  private String applicationId;
+  private String lifetime = null;
+  private Map<String, String> quicklinks;
+  private Integer numContainers;
+  private Integer expectedContainers;
+  private ArrayList<Map<String, Object>> containers;
+
+  public ServiceGroupResponse(Long clusterId, String clusterName, String serviceGroupName, String serviceGroupDisplayName,
+                              String serviceGroupType, String assemblyFile, String desiredState, String currentState) {
+    this.clusterId = clusterId;
+    this.clusterName = clusterName;
+    this.serviceGroupName = serviceGroupName;
+    this.serviceGroupDisplayName = serviceGroupDisplayName;
+    this.serviceGroupType = serviceGroupType;
+    this.assemblyFile = assemblyFile;
+    this.desiredState = desiredState;
+    this.currentState = currentState;
+  }
+
+  /**
+   * @return the clusterId
+   */
+  public Long getClusterId() {
+    return clusterId;
+  }
+
+  /**
+   * @param clusterId the clusterId to set
+   */
+  public void setClusterId(Long clusterId) {
+    this.clusterId = clusterId;
+  }
+
+  /**
+   * @return the clusterName
+   */
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  /**
+   * @param clusterName the clusterName to set
+   */
+  public void setClusterName(String clusterName) {
+    this.clusterName = clusterName;
+  }
+
+  /**
+   * @return the service group name
+   */
+  public String getServiceGroupName() {
+    return serviceGroupName;
+  }
+
+  /**
+   * @param  serviceGroupName the service group name
+   */
+  public void setServiceGroupName(String serviceGroupName) {
+    this.serviceGroupName = serviceGroupName;
+  }
+
+  /**
+   * @return the service group display name
+   */
+  public String getServiceGroupDisplayName() {
+    return serviceGroupDisplayName;
+  }
+
+  /**
+   * @param  serviceGroupDisplayName the service group display name
+   */
+  public void setServiceGroupDisplayName(String serviceGroupDisplayName) {
+    this.serviceGroupDisplayName = serviceGroupDisplayName;
+  }
+
+  /**
+   * @return the desired state of the service group
+   */
+  public String getDesiredState() {
+    return desiredState;
+  }
+
+  /**
+   * @param  desiredState the desired state of the service group
+   */
+  public void setDesiredState(String desiredState) {
+    this.desiredState = desiredState;
+  }
+
+  /**
+   * @return the current state of the service group
+   */
+  public String getCurrentState() {
+    return currentState;
+  }
+
+  /**
+   * @param  currentState the current state of the service group
+   */
+  public void setCurrentState(String currentState) {
+    this.currentState = currentState;
+  }
+
+
+  /**
+   * @return the service group type
+   */
+  public String getServiceGroupType() {
+    return serviceGroupType;
+  }
+
+  /**
+   * @param  serviceGroupType the service group type
+   */
+  public void setServiceGroupType(String serviceGroupType) {
+    this.serviceGroupType = serviceGroupType;
+  }
+
+  /**
+   * @return the assembly file
+   */
+  public String getAssemblyFile() {
+    return assemblyFile;
+  }
+
+  /**
+   * @param  assemblyFile the assembly file
+   */
+  public void setAssemblyFile(String assemblyFile) {
+    this.assemblyFile = assemblyFile;
+  }
+
+  public String getApplicationId() {
+    return applicationId;
+  }
+
+  public void setApplicationId(String applicationId) {
+    this.applicationId = applicationId;
+  }
+
+  public Map<String, String> getQuickLinks() {
+    return quicklinks;
+  }
+
+  public void setQuickLinks(Map<String, String> quicklinks) {
+    this.quicklinks = quicklinks;
+  }
+
+  public ArrayList<Map<String, Object>> getContainers() {
+    return containers;
+  }
+
+  public void setContainers(ArrayList<Map<String, Object>> containers) {
+    this.containers = containers;
+  }
+
+
+  public Integer getNumContainers() {
+    return numContainers;
+  }
+
+  public void setNumContainers(Integer numContainers) {
+    this.numContainers = numContainers;
+  }
+
+  public Integer getExpectedContainers() {
+    return expectedContainers;
+  }
+
+  public void setExpectedContainers(Integer expectedContainers) {
+    this.expectedContainers = expectedContainers;
+  }
+
+  public String getLifetime() {
+    return lifetime;
+  }
+
+  public void setLifetime(String lifetime) {
+    this.lifetime = lifetime;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ServiceGroupResponse that = (ServiceGroupResponse) o;
+
+    if (clusterId != null ?
+        !clusterId.equals(that.clusterId) : that.clusterId != null) {
+      return false;
+    }
+    if (clusterName != null ?
+        !clusterName.equals(that.clusterName) : that.clusterName != null) {
+      return false;
+    }
+    if (serviceGroupName != null ?
+        !serviceGroupName.equals(that.serviceGroupName) : that.serviceGroupName != null) {
+      return false;
+    }
+
+    return true;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceRequest.java
index eb874b5..4f9b1e8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceRequest.java
@@ -23,13 +23,17 @@ public class ServiceRequest {
 
   private String clusterName; // REF
   private String serviceName; // GET/CREATE/UPDATE/DELETE
+  private String stackServiceName; // GET/CREATE/UPDATE/DELETE
+  private String serviceGroupName; // GET/CREATE/UPDATE/DELETE
   private String desiredState; // CREATE/UPDATE
   private String maintenanceState; // UPDATE
 
-  public ServiceRequest(String clusterName, String serviceName,
-                        String desiredState) {
+  public ServiceRequest(String clusterName, String serviceName, String stackServiceName,
+    String serviceGroupName, String desiredState) {
     this.clusterName = clusterName;
     this.serviceName = serviceName;
+    this.stackServiceName = stackServiceName;
+    this.serviceGroupName = serviceGroupName;
     this.desiredState = desiredState;
   }
 
@@ -48,6 +52,34 @@ public class ServiceRequest {
   }
 
   /**
+   * @return the serviceName
+   */
+  public String getStackServiceName() {
+    return stackServiceName;
+  }
+
+  /**
+   * @param stackServiceName the actual serviceName to set
+   */
+  public void setStackServiceName(String stackServiceName) {
+    this.stackServiceName = stackServiceName;
+  }
+
+  /**
+   * @return the serviceGroupName
+   */
+  public String getServiceGroupName() {
+    return serviceGroupName;
+  }
+
+  /**
+   * @param serviceGroupName the service group name to set
+   */
+  public void setServiceGroupName(String serviceGroupName) {
+    this.serviceGroupName = serviceGroupName;
+  }
+
+  /**
    * @return the desiredState
    */
   public String getDesiredState() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java
index c4881b8..3fd4af6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java
@@ -24,16 +24,20 @@ public class ServiceResponse {
   private Long clusterId;
   private String clusterName;
   private String serviceName;
+  private String stackServiceName;
+  private String serviceGroupName;
   private String desiredStackVersion;
   private String desiredState;
   private String maintenanceState;
 
   public ServiceResponse(Long clusterId, String clusterName,
-                         String serviceName,
+                         String serviceName, String stackServiceName, String serviceGroupName,
                          String desiredStackVersion, String desiredState) {
     this.clusterId = clusterId;
     this.clusterName = clusterName;
     this.serviceName = serviceName;
+    this.serviceGroupName = serviceGroupName;
+    this.stackServiceName = stackServiceName;
     this.setDesiredStackVersion(desiredStackVersion);
     this.setDesiredState(desiredState);
   }
@@ -55,6 +59,34 @@ public class ServiceResponse {
   }
 
   /**
+   * @return the real serviceName
+   */
+  public String getStackServiceName() {
+    return stackServiceName;
+  }
+
+  /**
+   * @param stackServiceName the real serviceName to set
+   */
+  public void setStackServiceName(String stackServiceName) {
+    this.stackServiceName = stackServiceName;
+  }
+
+  /**
+   * @return the service group name
+   */
+  public String getServiceGroupName() {
+    return serviceGroupName;
+  }
+
+  /**
+   * @param  serviceGroupName the service group name
+   */
+  public void setServiceGroupName(String serviceGroupName) {
+    this.serviceGroupName = serviceGroupName;
+  }
+
+  /**
    * @return the clusterId
    */
   public Long getClusterId() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
index 3721113..80b8baa 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
@@ -131,6 +131,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractAuthori
         return new ClusterResourceProvider(managementController);
       case Service:
         return resourceProviderFactory.getServiceResourceProvider(propertyIds, keyPropertyIds, managementController);
+      case ServiceGroup:
+        return resourceProviderFactory.getServiceGroupResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Component:
         return resourceProviderFactory.getComponentResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Host:

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ComponentResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ComponentResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ComponentResourceProvider.java
index dd2b31b..cdcca30 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ComponentResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ComponentResourceProvider.java
@@ -27,18 +27,17 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.ClusterNotFoundException;
-import org.apache.ambari.server.DuplicateResourceException;
-import org.apache.ambari.server.ObjectNotFoundException;
-import org.apache.ambari.server.ParentObjectNotFoundException;
-import org.apache.ambari.server.ServiceNotFoundException;
+import jline.internal.Log;
+import org.apache.ambari.server.*;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.MaintenanceStateHelper;
 import org.apache.ambari.server.controller.RequestStatusResponse;
 import org.apache.ambari.server.controller.ServiceComponentRequest;
 import org.apache.ambari.server.controller.ServiceComponentResponse;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCache;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCacheKey;
+import org.apache.ambari.server.controller.servicegroup.cache.ServiceGroupCacheProvider;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
@@ -52,19 +51,12 @@ import org.apache.ambari.server.security.authorization.AuthorizationException;
 import org.apache.ambari.server.security.authorization.AuthorizationHelper;
 import org.apache.ambari.server.security.authorization.ResourceType;
 import org.apache.ambari.server.security.authorization.RoleAuthorization;
-import org.apache.ambari.server.state.Cluster;
-import org.apache.ambari.server.state.Clusters;
-import org.apache.ambari.server.state.ComponentInfo;
-import org.apache.ambari.server.state.Service;
-import org.apache.ambari.server.state.ServiceComponent;
-import org.apache.ambari.server.state.ServiceComponentFactory;
-import org.apache.ambari.server.state.ServiceComponentHost;
-import org.apache.ambari.server.state.StackId;
-import org.apache.ambari.server.state.State;
+import org.apache.ambari.server.state.*;
 
 import com.google.inject.assistedinject.Assisted;
 import com.google.inject.assistedinject.AssistedInject;
 import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.utils.MapUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.Validate;
 
@@ -81,6 +73,7 @@ public class ComponentResourceProvider extends AbstractControllerResourceProvide
   protected static final String COMPONENT_COMPONENT_NAME_PROPERTY_ID  = "ServiceComponentInfo/component_name";
   protected static final String COMPONENT_DISPLAY_NAME_PROPERTY_ID    = "ServiceComponentInfo/display_name";
   protected static final String COMPONENT_STATE_PROPERTY_ID           = "ServiceComponentInfo/state";
+  protected static final String COMPONENT_DESIRED_COUNT_PROPERTY_ID    = "ServiceComponentInfo/desired_count";
   protected static final String COMPONENT_CATEGORY_PROPERTY_ID        = "ServiceComponentInfo/category";
   protected static final String COMPONENT_TOTAL_COUNT_PROPERTY_ID     = "ServiceComponentInfo/total_count";
   protected static final String COMPONENT_STARTED_COUNT_PROPERTY_ID   = "ServiceComponentInfo/started_count";
@@ -100,6 +93,11 @@ public class ComponentResourceProvider extends AbstractControllerResourceProvide
 
   private MaintenanceStateHelper maintenanceStateHelper;
 
+  private static Map<String, String> componentNameMappings = MapUtils.fillMap("/var/lib/ambari-server/resources/componentsMap.dat");
+
+  private ServiceGroupCacheProvider cacheProvider;
+  private ServiceGroupCache cache;
+
   // ----- Constructors ----------------------------------------------------
 
   /**
@@ -122,6 +120,9 @@ public class ComponentResourceProvider extends AbstractControllerResourceProvide
     setRequiredGetAuthorizations(RoleAuthorization.AUTHORIZATIONS_VIEW_SERVICE);
     setRequiredGetAuthorizations(RoleAuthorization.AUTHORIZATIONS_VIEW_SERVICE);
     setRequiredUpdateAuthorizations(RoleAuthorization.AUTHORIZATIONS_UPDATE_CLUSTER);
+
+    this.cacheProvider = managementController.getServiceGroupCacheProvider();
+    this.cache = cacheProvider.getServiceGroupCache();
   }
 
 
@@ -180,6 +181,7 @@ public class ComponentResourceProvider extends AbstractControllerResourceProvide
       setResourceProperty(resource, COMPONENT_CATEGORY_PROPERTY_ID, response.getCategory(), requestedIds);
       setResourceProperty(resource, COMPONENT_TOTAL_COUNT_PROPERTY_ID, response.getTotalCount(), requestedIds);
       setResourceProperty(resource, COMPONENT_STARTED_COUNT_PROPERTY_ID, response.getStartedCount(), requestedIds);
+      setResourceProperty(resource, COMPONENT_DESIRED_COUNT_PROPERTY_ID, response.getDesiredCount(), requestedIds);
       setResourceProperty(resource, COMPONENT_INSTALLED_COUNT_PROPERTY_ID, response.getInstalledCount(), requestedIds);
       setResourceProperty(resource, COMPONENT_RECOVERY_ENABLED_ID, String.valueOf(response.isRecoveryEnabled()), requestedIds);
 
@@ -255,6 +257,7 @@ public class ComponentResourceProvider extends AbstractControllerResourceProvide
         (String) properties.get(COMPONENT_SERVICE_NAME_PROPERTY_ID),
         (String) properties.get(COMPONENT_COMPONENT_NAME_PROPERTY_ID),
         (String) properties.get(COMPONENT_STATE_PROPERTY_ID),
+        (String) properties.get(COMPONENT_DESIRED_COUNT_PROPERTY_ID),
         (String) properties.get(COMPONENT_RECOVERY_ENABLED_ID),
         (String) properties.get(COMPONENT_CATEGORY_PROPERTY_ID));
   }
@@ -351,6 +354,11 @@ public class ComponentResourceProvider extends AbstractControllerResourceProvide
       } else {
         sc.setDesiredState(s.getDesiredState());
       }
+      int desiredCount = 0;
+      if(StringUtils.isNotEmpty(request.getDesiredCount())) {
+        desiredCount = Integer.parseInt(request.getDesiredCount());
+      }
+      sc.setDesiredCount(desiredCount);
 
       /**
        * If request does not have recovery_enabled field,
@@ -395,8 +403,9 @@ public class ComponentResourceProvider extends AbstractControllerResourceProvide
   // Get the components for the given request.
   private Set<ServiceComponentResponse> getComponents(ServiceComponentRequest request) throws AmbariException {
 
-    final AmbariMetaInfo ambariMetaInfo = getManagementController().getAmbariMetaInfo();
-    final Clusters clusters = getManagementController().getClusters();
+    AmbariManagementController controller = getManagementController();
+    final AmbariMetaInfo ambariMetaInfo = controller.getAmbariMetaInfo();
+    final Clusters clusters = controller.getClusters();
     final Cluster cluster = getCluster(request, clusters);
 
     Set<ServiceComponentResponse> response = new HashSet<>();
@@ -410,6 +419,49 @@ public class ComponentResourceProvider extends AbstractControllerResourceProvide
       final Service s = getServiceFromCluster(request, cluster);
       ServiceComponent sc = s.getServiceComponent(request.getComponentName());
       ServiceComponentResponse serviceComponentResponse = sc.convertToResponse();
+      ServiceGroup sg = null;
+      try {
+        sg = cluster.getServiceGroup(sc.getServiceGroupName());
+      } catch (ServiceGroupNotFoundException e) {
+        sg = null;
+      }
+      if(sg != null && !sg.getServiceGroupType().equalsIgnoreCase("AMBARI")) {
+        ServiceGroupCacheKey cacheKey = new ServiceGroupCacheKey(sg.getName());
+        Map<String, Object> responseMap = null;
+        try {
+          responseMap = cache.getResponseFromCache(cacheKey);
+        } catch (Exception e) {
+          Log.info("Hit exception when retrieving service group from cache. Exception: " + e.getMessage());
+        }
+        if (responseMap != null && responseMap.containsKey("containers")) {
+          String mappedComponentName = componentNameMappings.containsKey(request.getComponentName()) ?
+              componentNameMappings.get(request.getComponentName()) : request.getComponentName();
+          int installedCount = 0;
+          int startedCount = 0;
+
+          for (Map<String, String> cMap : (ArrayList<Map<String, String>>) responseMap.get("containers")) {
+            String dashContainerName = cMap.get("id");
+            String dashComponentName = cMap.get("component_name");
+            String dashState = cMap.get("state");
+            String dashHostName = cMap.get("hostname");
+            String dashBareHostName = cMap.get("bare_host");
+            if (dashComponentName.contains(mappedComponentName)) {
+              if (dashState.equalsIgnoreCase("READY")) {
+                if (sc.isClientComponent()) {
+                  installedCount++;
+                } else {
+                  startedCount++;
+                }
+              } else {
+                installedCount++;
+              }
+            }
+          }
+          serviceComponentResponse.setInstalledCount(installedCount);
+          serviceComponentResponse.setStartedCount(startedCount);
+        }
+      }
+
 
       try {
         ComponentInfo componentInfo = ambariMetaInfo.getComponent(stackId.getStackName(),
@@ -443,6 +495,48 @@ public class ComponentResourceProvider extends AbstractControllerResourceProvide
         }
 
         ServiceComponentResponse serviceComponentResponse = sc.convertToResponse();
+        ServiceGroup sg = null;
+        try {
+          sg = cluster.getServiceGroup(sc.getServiceGroupName());
+        } catch (ServiceGroupNotFoundException e) {
+          sg = null;
+        }
+        if(sg != null && !sg.getServiceGroupType().equalsIgnoreCase("AMBARI")) {
+          ServiceGroupCacheKey cacheKey = new ServiceGroupCacheKey(sg.getName());
+          Map<String, Object> responseMap = null;
+          try {
+            responseMap = cache.getResponseFromCache(cacheKey);
+          } catch (Exception e) {
+            Log.info("Hit exception when retrieving service group from cache. Exception: " + e.getMessage());
+          }
+          if (responseMap != null && responseMap.containsKey("containers")) {
+            String mappedComponentName = componentNameMappings.containsKey(sc.getName()) ?
+                componentNameMappings.get(sc.getName()) : sc.getName();
+            int installedCount = 0;
+            int startedCount = 0;
+
+            for (Map<String, String> cMap : (ArrayList<Map<String, String>>) responseMap.get("containers")) {
+              String dashContainerName = cMap.get("id");
+              String dashComponentName = cMap.get("component_name");
+              String dashState = cMap.get("state");
+              String dashHostName = cMap.get("hostname");
+              String dashBareHostName = cMap.get("bare_host");
+              if (dashComponentName.contains(mappedComponentName)) {
+                if (dashState.equalsIgnoreCase("READY")) {
+                  if (sc.isClientComponent()) {
+                    installedCount++;
+                  } else {
+                    startedCount++;
+                  }
+                } else {
+                  installedCount++;
+                }
+              }
+            }
+            serviceComponentResponse.setInstalledCount(installedCount);
+            serviceComponentResponse.setStartedCount(startedCount);
+          }
+        }
         try {
           ComponentInfo componentInfo = ambariMetaInfo.getComponent(stackId.getStackName(),
               stackId.getStackVersion(), s.getName(), sc.getName());

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DashHttpPropertyRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DashHttpPropertyRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DashHttpPropertyRequest.java
new file mode 100644
index 0000000..76537f6
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DashHttpPropertyRequest.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller.internal;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.state.Cluster;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class DashHttpPropertyRequest extends JsonHttpPropertyRequest {
+
+  private static String DashApplicationsUrl = "http://cn008.l42scl.hortonworks.com:9191/services/v1/applications";
+
+  /**
+   * Create a property request.
+   *
+   * @param propertyMappings the property name mapping
+   */
+  public DashHttpPropertyRequest(Map<String, String> propertyMappings) {
+    super(propertyMappings);
+  }
+
+  @Override
+  public String getUrl(Cluster cluster, String hostName) throws SystemException {
+    return DashApplicationsUrl;
+  }
+
+  public String getUrl(Cluster cluster, String hostName, String yarnAppName) throws SystemException {
+    return DashApplicationsUrl + "/" + yarnAppName;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
index 9d8389a..3258b29 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
@@ -89,6 +89,10 @@ public class HostComponentResourceProvider extends AbstractControllerResourcePro
       = PropertyHelper.getPropertyId("HostRoles", "display_name");
   public static final String HOST_COMPONENT_HOST_NAME_PROPERTY_ID
       = PropertyHelper.getPropertyId("HostRoles", "host_name");
+  public static final String HOST_COMPONENT_BARE_HOST_NAME_PROPERTY_ID
+      = PropertyHelper.getPropertyId("HostRoles", "bare_host_name");
+  public static final String HOST_COMPONENT_CONTAINER_NAME_PROPERTY_ID
+      = PropertyHelper.getPropertyId("HostRoles", "container_name");
   public static final String HOST_COMPONENT_STATE_PROPERTY_ID
       = PropertyHelper.getPropertyId("HostRoles", "state");
   public static final String HOST_COMPONENT_DESIRED_STATE_PROPERTY_ID
@@ -227,6 +231,10 @@ public class HostComponentResourceProvider extends AbstractControllerResourcePro
               response.getDisplayName(), requestedIds);
       setResourceProperty(resource, HOST_COMPONENT_HOST_NAME_PROPERTY_ID,
               response.getHostname(), requestedIds);
+      setResourceProperty(resource, HOST_COMPONENT_BARE_HOST_NAME_PROPERTY_ID,
+          response.getBareHostName(), requestedIds);
+      setResourceProperty(resource, HOST_COMPONENT_CONTAINER_NAME_PROPERTY_ID,
+          response.getContainerName(), requestedIds);
       setResourceProperty(resource, HOST_COMPONENT_STATE_PROPERTY_ID,
               response.getLiveState(), requestedIds);
       setResourceProperty(resource, HOST_COMPONENT_DESIRED_STATE_PROPERTY_ID,


[10/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/queries.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/queries.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/queries.js
new file mode 100644
index 0000000..cbf6b42
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/queries.js
@@ -0,0 +1,125 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Ember from 'ember';
+import FilterableMixin from 'hive/mixins/filterable';
+import constants from 'hive/utils/constants';
+
+export default Ember.ArrayController.extend(FilterableMixin, {
+  needs: [ constants.namingConventions.routes.history,
+           constants.namingConventions.openQueries ],
+
+  history: Ember.computed.alias('controllers.' + constants.namingConventions.routes.history),
+  openQueries: Ember.computed.alias('controllers.' + constants.namingConventions.openQueries),
+
+  sortAscending: true,
+  sortProperties: [],
+
+  init: function () {
+    this._super();
+
+    this.set('columns', Ember.ArrayProxy.create({ content: Ember.A([
+       Ember.Object.create({
+        caption: "columns.shortQuery",
+        property: 'shortQuery',
+        link: constants.namingConventions.subroutes.savedQuery
+      }),
+      Ember.Object.create({
+        caption: "columns.title",
+        property: 'title',
+        link: constants.namingConventions.subroutes.savedQuery
+      }),
+      Ember.Object.create({
+        caption: "columns.database",
+        property: 'dataBase',
+        link: constants.namingConventions.subroutes.savedQuery
+      }),
+      Ember.Object.create({
+        caption: "columns.owner",
+        property: 'owner',
+        link: constants.namingConventions.subroutes.savedQuery
+      })
+    ])}));
+  },
+
+  //row buttons
+  links: [
+    "buttons.history",
+    "buttons.delete"
+  ],
+
+  model: function () {
+    return this.filter(this.get('queries'));
+  }.property('queries', 'filters.@each'),
+
+  actions: {
+    executeAction: function (action, savedQuery) {
+      var self = this;
+
+      switch (action) {
+        case "buttons.history":
+          this.get('history').filterBy('queryId', savedQuery.get('id'), true);
+          this.transitionToRoute(constants.namingConventions.routes.history);
+          break;
+        case "buttons.delete":
+          var defer = Ember.RSVP.defer();
+          this.send('openModal',
+                    'modal-delete',
+                     {
+                        heading: "modals.delete.heading",
+                        text: "modals.delete.message",
+                        defer: defer
+                     });
+
+          defer.promise.then(function () {
+            savedQuery.destroyRecord();
+            self.get('openQueries').updatedDeletedQueryTab(savedQuery);
+          });
+
+          break;
+      }
+    },
+
+    sort: function (property) {
+      //if same column has been selected, toggle flag, else default it to true
+      if (this.get('sortProperties').objectAt(0) === property) {
+        this.set('sortAscending', !this.get('sortAscending'));
+      } else {
+        this.set('sortAscending', true);
+        this.set('sortProperties', [ property ]);
+      }
+    },
+
+    clearFilters: function () {
+      var columns = this.get('columns');
+
+      if (columns) {
+        columns.forEach(function (column) {
+          var filterValue = column.get('filterValue');
+
+          if (filterValue && typeof filterValue === 'string') {
+            column.set('filterValue');
+          }
+        });
+      }
+
+      //call clear filters from Filterable mixin
+      this.clearFilters();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/query-tabs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/query-tabs.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/query-tabs.js
new file mode 100644
index 0000000..5f31c19
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/query-tabs.js
@@ -0,0 +1,176 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+  jobProgressService: Ember.inject.service(constants.namingConventions.jobProgress),
+  openQueries   : Ember.inject.controller(constants.namingConventions.openQueries),
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+  index: Ember.inject.controller(),
+
+  tabClassNames : "fa queries-icon query-context-tab",
+
+  tabs: [
+    Ember.Object.create({
+      iconClass: 'text-icon',
+      id: 'query-icon',
+      text: 'SQL',
+      action: 'setDefaultActive',
+      name: constants.namingConventions.index,
+      tooltip: Ember.I18n.t('tooltips.query')
+    }),
+    Ember.Object.create({
+      iconClass: 'fa-gear',
+      id: 'settings-icon',
+      action: 'toggleOverlay',
+      template: 'settings',
+      outlet: 'overlay',
+      into: 'open-queries',
+      tooltip: Ember.I18n.t('tooltips.settings')
+    }),
+    Ember.Object.create({
+      iconClass: 'fa-area-chart',
+      id: 'visualization-icon',
+      action: 'toggleOverlay',
+      tooltip: Ember.I18n.t('tooltips.visualization'),
+      into: 'index',
+      outlet: 'overlay',
+      template: 'visualization-ui',
+      onTabOpen: 'onTabOpen'
+    }),
+    Ember.Object.create({
+      iconClass: 'fa-link',
+      id: 'visual-explain-icon',
+      action: 'toggleOverlay',
+      template: 'visual-explain',
+      outlet: 'overlay',
+      into: 'index',
+      onTabOpen: 'onTabOpen',
+      tooltip: Ember.I18n.t('tooltips.visualExplain')
+    }),
+    Ember.Object.create({
+      iconClass: 'text-icon',
+      id: 'tez-icon',
+      text: 'TEZ',
+      action: 'toggleOverlay',
+      template: 'tez-ui',
+      outlet: 'overlay',
+      into: 'index',
+      tooltip: Ember.I18n.t('tooltips.tez')
+    }),
+    Ember.Object.create({
+      iconClass: 'fa-envelope',
+      id: 'notifications-icon',
+      action: 'toggleOverlay',
+      template: 'messages',
+      outlet: 'overlay',
+      into: 'index',
+      badgeProperty: 'count',
+      onTabOpen: 'markMessagesAsSeen',
+      tooltip: Ember.I18n.t('tooltips.notifications')
+    })
+  ],
+
+  init: function() {
+    this.setupControllers();
+    this.setDefaultTab();
+    this.setupTabsBadges();
+  },
+
+  setupControllers: function() {
+    var tabs = this.get('tabs');
+    var self = this;
+
+    tabs.map(function (tab) {
+      var controller;
+
+      if (tab.get('template')) {
+        controller = self.container.lookup('controller:' + tab.get('template'));
+        tab.set('controller', controller);
+      }
+    });
+  },
+
+  setDefaultTab: function () {
+    var defaultTab = this.get('tabs.firstObject');
+
+    defaultTab.set('active', true);
+
+    this.set('default', defaultTab);
+    this.set('activeTab', defaultTab);
+  },
+
+  setupTabsBadges: function () {
+    var tabs = this.get('tabs').filterProperty('badgeProperty');
+
+    tabs.map(function (tab) {
+        Ember.oneWay(tab, 'badge', 'controller.' + tab.badgeProperty);
+    });
+  },
+
+  closeActiveOverlay: function () {
+    this.send('closeOverlay', this.get('activeTab'));
+  },
+
+  onTabOpen: function (tab) {
+    if (!tab.onTabOpen) {
+      return;
+    }
+
+    var controller = this.container.lookup('controller:' + tab.template);
+    controller.send(tab.onTabOpen, controller);
+  },
+
+  openOverlay: function (tab) {
+    this.closeActiveOverlay();
+    this.set('activeTab.active', false);
+    tab.set('active', true);
+    this.set('activeTab', tab);
+
+    this.onTabOpen(tab);
+    this.send('openOverlay', tab);
+  },
+
+  setDefaultActive: function () {
+    var activeTab = this.get('activeTab');
+    var defaultTab = this.get('default');
+
+    if (activeTab !== defaultTab) {
+      this.closeActiveOverlay();
+      defaultTab.set('active', true);
+      activeTab.set('active', false);
+      this.set('activeTab', defaultTab);
+    }
+  },
+
+  actions: {
+    toggleOverlay: function (tab) {
+      if (tab !== this.get('default') && tab.get('active')) {
+        this.setDefaultActive();
+      } else {
+        this.openOverlay(tab);
+      }
+    },
+
+    setDefaultActive: function () {
+      this.setDefaultActive();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/settings.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/settings.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/settings.js
new file mode 100644
index 0000000..77250b4
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/settings.js
@@ -0,0 +1,69 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+  openQueries: Ember.inject.controller(),
+  index: Ember.inject.controller(),
+
+  settingsService: Ember.inject.service('settings'),
+
+  predefinedSettings: Ember.computed.alias('settingsService.predefinedSettings'),
+  settings: Ember.computed.alias('settingsService.settings'),
+
+  init: function() {
+    this._super();
+
+    this.get('settingsService').loadDefaultSettings();
+  },
+
+  excluded: function() {
+    var settings = this.get('settings');
+
+    return this.get('predefinedSettings').filter(function(setting) {
+      return settings.findBy('key.name', setting.name);
+    });
+  }.property('settings.@each.key'),
+
+  parseGlobalSettings: function () {
+    this.get('settingsService').parseGlobalSettings(this.get('openQueries.currentQuery'), this.get('index.model'));
+  }.observes('openQueries.currentQuery', 'openQueries.currentQuery.fileContent', 'openQueries.tabUpdated').on('init'),
+
+  actions: {
+    add: function () {
+      this.get('settingsService').add();
+    },
+
+    remove: function (setting) {
+      this.get('settingsService').remove(setting);
+    },
+
+    addKey: function (name) {
+      this.get('settingsService').createKey(name);
+    },
+
+    removeAll: function () {
+      this.get('settingsService').removeAll();
+    },
+
+    saveDefaultSettings: function() {
+      this.get('settingsService').saveDefaultSettings();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js
new file mode 100644
index 0000000..5db93f7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js
@@ -0,0 +1,126 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+
+  databaseService: Ember.inject.service(constants.namingConventions.database),
+  isExpanded: false,
+  errors: "",
+  stackTrace: "",
+  startTests: function() {
+
+    var model = this.get('model');
+    var url = this.container.lookup('adapter:application').buildURL() + '/resources/hive/'
+    var self = this;
+
+    var processResponse = function(name, data) {
+
+      if( data != undefined ){
+        if(data.databases){
+          data = Ember.Object.create( {trace: null, message: "OK", status: "200"});
+        } else {
+          data = data;
+        }
+      } else {
+        data = Ember.Object.create( {trace: null, message: "Server Error", status: "500"});
+      }
+
+      model.set(name + 'Test', data.status == 200);
+
+      if (data.status != 200) {
+        var checkFailedMessage = "Service '" + name + "' check failed";
+        var errors = self.get("errors");
+        errors += checkFailedMessage;
+        errors += (data.message)?(': <i>' + data.message + '</i><br>'):'<br>';
+        self.set("errors", errors);
+      }
+
+      if (data.trace != null) {
+        var stackTrace = self.get("stackTrace");
+        stackTrace += checkFailedMessage + ':\n' + data.trace;
+        self.set("stackTrace", stackTrace);
+      }
+
+      model.set(name + 'TestDone', true);
+
+      var percent = model.get('percent');
+      model.set('percent', percent + 33.33);
+    };
+
+    var promises = ['hdfs', 'hiveserver', 'ats'].map(function(name) {
+
+      var finalurl = ((name == 'hiveserver') ? self.get('databaseService.baseUrl') : (url + name + 'Status')) || '' ;
+
+      return Ember.$.getJSON( finalurl )
+        .then(
+          function(data) {
+            processResponse(name, data);
+          },
+          function(reason) {
+            processResponse(name, reason.responseJSON);
+          }
+        );
+    });
+
+    return Ember.RSVP.all(promises);
+  },
+
+  progressBarStyle: function() {
+    return 'width: ' + this.get("model").get("percent") +  '%;';
+  }.property("model.percent"),
+
+  allTestsCompleted: function(){
+    return this.get('modelhdfsTestDone') && this.get('modelhiveserverTestDone') && this.get('modelatsTestDone');
+  }.property('modelhdfsTestDone', 'modelhiveserverTestDone', 'modelatsTestDone'),
+
+  modelhdfsTestDone: function() {
+    return this.get('model.hdfsTestDone');
+  }.property('model.hdfsTestDone' ),
+
+  modelhiveserverTestDone: function() {
+    return this.get('model.hiveserverTestDone');
+  }.property('model.hiveserverTestDone' ),
+
+  modelatsTestDone: function() {
+    return this.get('model.atsTestDone');
+  }.property('model.atsTestDone' ),
+
+  modelhdfsTest: function() {
+    return this.get('model.hdfsTest');
+  }.property('model.hdfsTest' ),
+
+  modelhiveserverTest: function() {
+    return this.get('model.hiveserverTest');
+  }.property('model.hiveserverTest' ),
+
+  modelatsTest: function() {
+    return this.get('model.atsTest');
+  }.property('model.atsTest' ),
+
+  actions: {
+    toggleStackTrace:function () {
+      var value = this.get('isExpanded');
+      this.set('isExpanded', !value);
+    }
+  }
+});
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/tez-ui.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/tez-ui.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/tez-ui.js
new file mode 100644
index 0000000..43835e0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/tez-ui.js
@@ -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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+  needs: [ constants.namingConventions.index ],
+
+  index: Ember.computed.alias('controllers.' + constants.namingConventions.index),
+
+  tezViewURL: null,
+  tezApiURL: '/api/v1/views/TEZ',
+  tezURLPrefix: '/views/TEZ',
+  tezDagPath: '?viewPath=/#/dag/',
+
+  isTezViewAvailable: Ember.computed.bool('tezViewURL'),
+
+  dagId: function () {
+    if (this.get('isTezViewAvailable')) {
+      return this.get('index.model.dagId');
+    }
+
+    return false;
+  }.property('index.model.dagId', 'isTezViewAvailable'),
+
+  dagURL: function () {
+    if (this.get('dagId')) {
+      return "%@%@%@".fmt(this.get('tezViewURL'), this.get('tezDagPath'), this.get('dagId'));
+    }
+
+    return false;
+  }.property('dagId'),
+
+  getTezView: function () {
+    if (this.get('isTezViewAvailable')) {
+      return;
+    }
+
+    var self = this;
+    Ember.$.getJSON(this.get('tezApiURL'))
+      .then(function (response) {
+        self.getTezViewInstance(response);
+      })
+      .fail(function (response) {
+        self.setTezViewError(response);
+      });
+  }.on('init'),
+
+  getTezViewInstance: function (data) {
+    var self = this;
+    var url = this.get('tezApiURL') + '/versions/' + data.versions[0].ViewVersionInfo.version;
+
+    Ember.$.getJSON(url)
+      .then(function (response) {
+        if (!response.instances.length) {
+          self.setTezViewError(response);
+          return;
+        }
+
+        self.set('isTezViewAvailable', true);
+
+        var instance = response.instances[0].ViewInstanceInfo;
+        self.setTezViewURL(instance);
+      });
+  },
+
+  setTezViewURL: function (instance) {
+    var url = "%@/%@/%@/".fmt(
+      this.get('tezURLPrefix'),
+      instance.version,
+      instance.instance_name
+    );
+
+    this.set('tezViewURL', url);
+  },
+
+  setTezViewError: function (data) {
+    // status: 404 => Tev View isn't deployed
+    if (data.status && data.status === 404) {
+      this.set('error', 'tez.errors.not.deployed');
+      return;
+    }
+
+    // no instance created
+    if (data.instances && !data.instances.length) {
+      this.set('error', 'tez.errors.no.instance');
+      return;
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/udfs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/udfs.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/udfs.js
new file mode 100644
index 0000000..3aec378
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/udfs.js
@@ -0,0 +1,143 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import FilterableMixin from 'hive/mixins/filterable';
+import constants from 'hive/utils/constants';
+
+export default Ember.ArrayController.extend(FilterableMixin, {
+  fileResources: [],
+
+  sortAscending: true,
+  sortProperties: [],
+
+  columns: [
+    Ember.Object.create({
+      caption: 'placeholders.udfs.name',
+      property: 'name'
+    }),
+    Ember.Object.create({
+      caption: 'placeholders.udfs.className',
+      property: 'classname'
+    })
+  ],
+
+  model: function () {
+    return this.filter(this.get('udfs'));
+  }.property('udfs', 'filters.@each'),
+
+  actions: {
+    handleAddFileResource: function (udf) {
+      var file = this.store.createRecord(constants.namingConventions.fileResource);
+      udf.set('fileResource', file);
+      udf.set('isEditingResource', true);
+    },
+
+    handleDeleteFileResource: function (file) {
+      var defer = Ember.RSVP.defer();
+
+      this.send('openModal',
+                'modal-delete',
+                 {
+                    heading: 'modals.delete.heading',
+                    text: 'modals.delete.message',
+                    defer: defer
+                 });
+
+      defer.promise.then(function () {
+        file.destroyRecord();
+      });
+    },
+
+    handleSaveUdf: function (udf) {
+      var self = this,
+          saveUdf = function () {
+            udf.save().then(function () {
+              udf.set('isEditing', false);
+              udf.set('isEditingResource', false);
+            });
+          };
+
+      //replace with a validation system if needed.
+      if (!udf.get('name') || !udf.get('classname')) {
+        return;
+      }
+
+      udf.get('fileResource').then(function (file) {
+        if (file) {
+          if (!file.get('name') || !file.get('path')) {
+            return;
+          }
+
+          file.save().then(function () {
+            saveUdf();
+          });
+        } else {
+          saveUdf();
+        }
+      });
+    },
+
+    handleDeleteUdf: function (udf) {
+      var defer = Ember.RSVP.defer();
+
+      this.send('openModal',
+                'modal-delete',
+                 {
+                    heading: 'modals.delete.heading',
+                    text: 'modals.delete.message',
+                    defer: defer
+                 });
+
+      defer.promise.then(function () {
+        udf.destroyRecord();
+      });
+    },
+
+    sort: function (property) {
+      //if same column has been selected, toggle flag, else default it to true
+      if (this.get('sortProperties').objectAt(0) === property) {
+        this.set('sortAscending', !this.get('sortAscending'));
+      } else {
+        this.set('sortAscending', true);
+        this.set('sortProperties', [ property ]);
+      }
+    },
+
+    add: function () {
+      this.store.createRecord(constants.namingConventions.udf);
+    },
+
+    clearFilters: function () {
+      var columns = this.get('columns');
+
+      if (columns) {
+        columns.forEach(function (column) {
+          var filterValue = column.get('filterValue');
+
+          if (filterValue && typeof filterValue === 'string') {
+            column.set('filterValue');
+          }
+        });
+      }
+
+      //call clear filters from Filterable mixin
+      this.clearFilters();
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/upload-table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/upload-table.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/upload-table.js
new file mode 100644
index 0000000..3f17760
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/upload-table.js
@@ -0,0 +1,740 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import Uploader from 'hive/adapters/upload-table'
+import constants from 'hive/utils/constants';
+
+
+export default Ember.Controller.extend({
+  isLocalUpload : Ember.computed.equal("uploadSource","local"),
+  uploadSource : "local",
+  hdfsPath : "",
+  jobService: Ember.inject.service(constants.namingConventions.job),
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+  needs: ['databases'],
+  showErrors: false,
+  uploader: Uploader.create(),
+  baseUrl: "/resources/upload",
+  isFirstRowHeader: true, // is first row  header
+  header: null,  // header received from server
+  files: null, // files that need to be uploaded only file[0] is relevant
+  firstRow: [], // the actual first row of the table.
+  rows: null,  // preview rows received from server
+  databaseName: null,
+  selectedDatabase: null,
+  filePath: null,
+  tableName: null,
+  uploadProgressInfos : [],
+  onChangeUploadSource : function(){
+    this.clearFields();
+  }.observes("uploadSource"),
+  uploadProgressInfo : Ember.computed("uploadProgressInfos.[]",function(){
+    var info = "";
+    for( var i = 0 ; i < this.get('uploadProgressInfos').length ; i++)
+        info += this.get('uploadProgressInfos').objectAt(i);
+
+    return new Ember.Handlebars.SafeString(info);
+  }),
+  inputFileTypes :[
+    {id : "CSV", name : "CSV"},
+    {id : "JSON", name : "JSON"},
+    {id : "XML", name : "XML"}
+  ],
+  inputFileType : {id : "CSV", name : "CSV"},
+  inputFileTypeCSV : Ember.computed.equal('inputFileType.id',"CSV"),
+  fileTypes:[
+    "SEQUENCEFILE",
+    "TEXTFILE"    ,
+    "RCFILE"      ,
+    "ORC"         ,
+    "PARQUET"     ,
+    "AVRO"        ,
+    "INPUTFORMAT"
+  ],
+  selectedFileType: "ORC",
+  dataTypes: [
+    "TINYINT", //
+    "SMALLINT", //
+    "INT", //
+    "BIGINT", //
+    "BOOLEAN", //
+    "FLOAT", //
+    "DOUBLE", //
+    "STRING", //
+    "BINARY", // -- (Note: Available in Hive 0.8.0 and later)
+    "TIMESTAMP", // -- (Note: Available in Hive 0.8.0 and later)
+    "DECIMAL", // -- (Note: Available in Hive 0.11.0 and later)
+    "DATE", // -- (Note: Available in Hive 0.12.0 and later)
+    "VARCHAR", // -- (Note: Available in Hive 0.12.0 and later)
+    "CHAR" // -- (Note: Available in Hive 0.13.0 and later)
+  ],
+  isFirstRowHeaderDidChange: function () {
+    console.log("inside onFirstRowHeader : isFirstRowHeader : " + this.get('isFirstRowHeader'));
+    if (this.get('isFirstRowHeader') != null && typeof this.get('isFirstRowHeader') !== 'undefined') {
+      if (this.get('isFirstRowHeader') == false) {
+        if (this.get('rows')) {
+          this.get('rows').unshiftObject({row: this.get('firstRow')});
+        }
+      } else if( this.get('header') ) { // headers are available
+        // take first row of
+        this.get('header').forEach(function (item, index) {
+          console.log("item : ", item);
+          console.log("this.get('firstRow').objectAt(index)  : ", this.get('firstRow').objectAt(index));
+          Ember.set(item, 'name', this.get('firstRow')[index]);
+        }, this);
+
+        this.get('rows').removeAt(0);
+      }
+
+      this.printValues();
+    }
+  }.observes('isFirstRowHeader'),
+
+  popUploadProgressInfos : function(){
+    var msg = this.get('uploadProgressInfos').popObject();
+   // console.log("popedup message : " + msg);
+  },
+
+  pushUploadProgressInfos : function(info){
+    this.get('uploadProgressInfos').pushObject(info);
+   // console.log("pushed message : " + info);
+  },
+
+  clearUploadProgressModal : function(){
+  //  console.log("inside clearUploadProgressModal this.get('uploadProgressInfos') : " + this.get('uploadProgressInfos'));
+    var len = this.get('uploadProgressInfos').length;
+    for( var i = 0 ; i < len ; i++){
+      this.popUploadProgressInfos();
+    }
+  },
+
+  hideUploadModal : function(){
+    console.log("hiding the modal ....");
+    this.clearUploadProgressModal();
+    Ember.$("#uploadProgressModal").modal("hide");
+  },
+
+  showUploadModal : function(){
+    Ember.$("#uploadProgressModal").modal("show");
+  },
+
+  clearFields: function () {
+    this.set("hdfsPath");
+    this.set("header");
+    this.set("rows");
+    this.set("error");
+    this.set('isFirstRowHeader',true);
+    this.set('files');
+    this.set("firstRow");
+    this.set("selectedDatabase",null);
+    this.set("databaseName");
+    this.set("filePath");
+    this.set('tableName');
+    this.clearUploadProgressModal();
+    this.printValues();
+  },
+
+  printValues: function () {
+    console.log("printing all values : ");
+    console.log("header : ", this.get('header'));
+    console.log("rows : ", this.get('rows'));
+    console.log("error : ", this.get('error'));
+    console.log("isFirstRowHeader : ", this.get('isFirstRowHeader'));
+    console.log("files : ", this.get('files'));
+    console.log("firstRow : ", this.get('firstRow'));
+  },
+
+  generateTempTableName : function(){
+    var text = "";
+    var possible = "abcdefghijklmnopqrstuvwxyz";
+
+    for( var i=0; i < 30; i++ )
+      text += possible.charAt(Math.floor(Math.random() * possible.length));
+
+    return text;
+  },
+
+  waitForJobStatus: function (jobId, resolve, reject) {
+    console.log("finding status of job: ", jobId);
+    var self = this;
+    var fetchJobPromise = this.get('jobService').fetchJobStatus(jobId);
+      fetchJobPromise.then(function (data) {
+        console.log("waitForJobStatus : data : ", data);
+        var status = data.jobStatus;
+        if (status == "SUCCEEDED") {
+          console.log("resolving waitForJobStatus with : " , status);
+          resolve(status);
+        } else if (status == "CANCELED" || status == "CLOSED" || status == "ERROR") {
+          console.log("rejecting waitForJobStatus with : " + status);
+          reject(new Error(status));
+        } else {
+          console.log("retrying waitForJobStatus : ");
+          self.waitForJobStatus(jobId, resolve, reject);
+        }
+      }, function (error) {
+        console.log("rejecting waitForJobStatus with : " + error);
+        reject(error);
+    })
+  },
+
+  uploadForPreview: function (files) {
+    console.log("uploaderForPreview called.");
+    var self = this;
+    return this.get('uploader').uploadFiles('preview', files, {"isFirstRowHeader" : self.get("isFirstRowHeader"), "inputFileType" : self.get("inputFileType").id});
+  },
+
+  uploadForPreviewFromHDFS : function(){
+    console.log("uploadForPreviewFromHDFS called.");
+    return this.get('uploader').previewFromHDFS({"isFirstRowHeader" : this.get("isFirstRowHeader"),"inputFileType" : this.get("inputFileType").id , "hdfsPath" : this.get("hdfsPath") });
+  },
+
+  generatePreview : function(files){
+    var self = this;
+    var promise = null;
+    this.waitForGeneratingPreview();
+    if(this.get('isLocalUpload')){
+      promise = this.uploadForPreview(files);
+    }else{
+      promise = this.uploadForPreviewFromHDFS();
+    }
+
+    return promise.then(function (data) {
+        self.onGeneratePreviewSuccess(data);
+    }, function (error) {
+        self.onGeneratePreviewFailure(error);
+    });
+  },
+
+  waitForGeneratingPreview: function () {
+    console.log("waitForGeneratingPreview");
+    this.showUploadModal();
+    this.pushUploadProgressInfos("<li> Generating Preview .... </li>")
+  },
+
+  previewTable: function (data) {
+    console.log('inside previewTable');
+    this.set("header", data.header);
+    this.set("firstRow", data.rows[0].row);
+    console.log("firstRow : ", this.get('firstRow'));
+    this.set('isFirstRowHeader', data.isFirstRowHeader);
+    this.set('tableName',data.tableName);
+    if(data.isFirstRowHeader == true){
+        data.rows = data.rows.slice(1);
+    }
+    this.set("rows", data.rows);
+  },
+
+  onGeneratePreviewSuccess: function (data) {
+    console.log("onGeneratePreviewSuccess");
+    this.hideUploadModal();
+    this.previewTable(data);
+  },
+
+  onGeneratePreviewFailure: function (error) {
+    console.log("onGeneratePreviewFailure");
+    this.hideUploadModal();
+    this.setError(error);
+  },
+
+  createTable: function () {
+    console.log("table headers : ", this.get('header'));
+    var headers = this.get('header');
+
+    var selectedDatabase = this.get('selectedDatabase');
+    if (null == selectedDatabase || typeof selectedDatabase === 'undefined') {
+      throw new Error(Ember.I18n.t('hive.errors.emptyDatabase'));
+    }
+
+    this.set('databaseName', this.get('selectedDatabase').get('name'));
+    var databaseName = this.get('databaseName');
+    var tableName = this.get('tableName');
+    var isFirstRowHeader = this.get('isFirstRowHeader');
+    var filetype = this.get("selectedFileType");
+
+    if (null == databaseName || typeof databaseName === 'undefined' || databaseName == '') {
+      throw new Error(Ember.I18n.t('hive.errors.emptyDatabase'));
+    }
+    if (null == tableName || typeof tableName === 'undefined' || tableName == '') {
+      throw new Error(Ember.I18n.t('hive.errors.emptyTableName'));
+    }
+    if (null == isFirstRowHeader || typeof isFirstRowHeader === 'undefined') {
+      throw new Error(Ember.I18n.t('hive.errors.emptyIsFirstRow'));
+    }
+
+    this.validateColumns();
+
+    return this.get('uploader').createTable({
+      "isFirstRowHeader": isFirstRowHeader,
+      "header": headers,
+      "tableName": tableName,
+      "databaseName": databaseName,
+      "fileType":filetype
+    });
+  },
+
+  createActualTable : function(){
+    console.log("createActualTable");
+    this.pushUploadProgressInfos("<li> Starting to create Actual table.... </li>");
+    return this.createTable();
+  },
+
+  waitForCreateActualTable: function (jobId) {
+    console.log("waitForCreateActualTable");
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Waiting for creation of Actual table.... </li>");
+    var self = this;
+    var p = new Ember.RSVP.Promise(function (resolve, reject) {
+      self.waitForJobStatus(jobId, resolve, reject);
+    });
+
+    return p;
+  },
+
+  onCreateActualTableSuccess : function(){
+    console.log("onCreateTableSuccess");
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Successfully created Actual table. </li>");
+  },
+
+  onCreateActualTableFailure : function(error){
+    console.log("onCreateActualTableFailure");
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Failed to create Actual table. </li>");
+    this.setError(error);
+  },
+
+  createTempTable : function(){
+    console.log("createTempTable");
+    this.pushUploadProgressInfos("<li> Starting to create Temporary table.... </li>");
+    var tempTableName = this.generateTempTableName();
+    this.set('tempTableName',tempTableName);
+    return this.get('uploader').createTable({
+      "isFirstRowHeader": this.get("isFirstRowHeader"),
+      "header": this.get("header"),
+      "tableName": tempTableName,
+      "databaseName": this.get('databaseName'),
+      "fileType":"TEXTFILE"
+    });
+  },
+
+  waitForCreateTempTable: function (jobId) {
+    console.log("waitForCreateTempTable");
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Waiting for creation of Temporary table.... </li>");
+    var self = this;
+    var p = new Ember.RSVP.Promise(function (resolve, reject) {
+      self.waitForJobStatus(jobId, resolve, reject);
+    });
+
+    return p;
+  },
+
+  onCreateTempTableSuccess : function(){
+    console.log("onCreateTempTableSuccess");
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Successfully created Temporary table. </li>");
+  },
+
+  deleteTable : function(databaseName, tableName){
+    console.log("deleting table " + databaseName + "." + tableName);
+
+    return this.get('uploader').deleteTable({
+      "database":  databaseName,
+      "table": tableName
+    });
+  },
+
+  deleteTableOnError : function(databaseName,tableName, tableLabel){
+      //delete table and wait for delete job
+    var self = this;
+    this.pushUploadProgressInfos("<li> Deleting " + tableLabel + " table...  </li>");
+
+    return this.deleteTable(databaseName,tableName).then(function(data){
+      return new Ember.RSVP.Promise(function(resolve,reject){
+        self.waitForJobStatus(data.jobId,resolve,reject);
+      });
+    }).then(function(){
+      self.popUploadProgressInfos();
+      self.pushUploadProgressInfos("<li> Successfully deleted " + tableLabel + " table. </li>");
+      return Ember.RSVP.Promise.resolve();
+    },function(err){
+      self.popUploadProgressInfos();
+      self.pushUploadProgressInfos("<li> Failed to delete " + tableLabel + " table. </li>");
+      self.setError(err);
+      return Ember.RSVP.Promise.reject();
+    });
+  },
+
+  rollBackActualTableCreation : function(){
+    return this.deleteTableOnError(this.get("databaseName"),this.get("tableName"),"Actual");
+  },
+
+
+  onCreateTempTableFailure : function(error){
+    console.log("onCreateTempTableFailure");
+    this.setError(error);
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Failed to create temporary table. </li>");
+    return this.rollBackActualTableCreation().then(function(data){
+      return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop
+    },function(err){
+      return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop
+    });
+  },
+
+  uploadFile : function(){
+    console.log("uploadFile");
+    this.pushUploadProgressInfos("<li> Starting to upload the file .... </li>");
+    if( this.get("isLocalUpload")){
+      return this.uploadTable();
+    }else{
+      return this.uploadTableFromHdfs();
+    }
+  },
+
+  waitForUploadingFile: function (data) {
+    console.log("waitForUploadingFile");
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Waiting for uploading file .... </li>");
+    if( data.jobId ){
+      var self = this;
+          var p = new Ember.RSVP.Promise(function (resolve, reject) {
+            self.waitForJobStatus(data.jobId, resolve, reject);
+          });
+      return p;
+    }else{
+      return  Ember.RSVP.Promise.resolve(data);
+    }
+  },
+
+  onUploadingFileSuccess: function () {
+    console.log("onUploadingFileSuccess");
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Successfully uploaded file. </li>");
+  },
+
+  rollBackTempTableCreation : function(){
+    var self = this;
+    return this.deleteTableOnError(this.get("databaseName"),this.get("tempTableName"),"Temporary").then(function(data){
+      return self.rollBackActualTableCreation();
+    },function(err){
+      return self.rollBackActualTableCreation();
+    })
+  },
+
+  onUploadingFileFailure: function (error) {
+    console.log("onUploadingFileFailure");
+    this.setError(error);
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Failed to upload file. </li>");
+    return this.rollBackTempTableCreation().then(function(data){
+      return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop
+    },function(err){
+      return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop
+    });
+  },
+
+  rollBackUploadFile : function(){
+    return this.rollBackTempTableCreation();
+  },
+
+  insertIntoTable : function(){
+    console.log("insertIntoTable");
+    this.pushUploadProgressInfos("<li> Starting to Insert rows from temporary table to actual table .... </li>");
+
+    return this.get('uploader').insertIntoTable({
+      "fromDatabase":  this.get("databaseName"),
+      "fromTable": this.get("tempTableName"),
+      "toDatabase": this.get("databaseName"),
+      "toTable": this.get("tableName")
+    });
+  },
+
+  waitForInsertIntoTable: function (jobId) {
+    console.log("waitForInsertIntoTable");
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Waiting for Insertion of rows from temporary table to actual table .... </li>");
+    var self = this;
+    var p = new Ember.RSVP.Promise(function (resolve, reject) {
+      self.waitForJobStatus(jobId, resolve, reject);
+    });
+
+    return p;
+  },
+
+  onInsertIntoTableSuccess : function(){
+    console.log("onInsertIntoTableSuccess");
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Successfully inserted rows from temporary table to actual table. </li>");
+  },
+
+  onInsertIntoTableFailure : function(error){
+    console.log("onInsertIntoTableFailure");
+    this.setError(error);
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Failed to insert rows from temporary table to actual table. </li>");
+    return this.rollBackUploadFile().then(function(data){
+      return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop
+    },function(err){
+      return Ember.RSVP.Promise.reject(error); // always reject for the flow to stop
+    });
+  },
+
+  deleteTempTable : function(){
+    console.log("deleteTempTable");
+    this.pushUploadProgressInfos("<li> Starting to delete temporary table .... </li>");
+
+    return this.deleteTable(
+      this.get("databaseName"),
+      this.get("tempTableName")
+    );
+  },
+
+  waitForDeleteTempTable: function (jobId) {
+    console.log("waitForDeleteTempTable");
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li> Waiting for deletion of temporary table .... </li>");
+    var self = this;
+    var p = new Ember.RSVP.Promise(function (resolve, reject) {
+      self.waitForJobStatus(jobId, resolve, reject);
+    });
+
+    return p;
+  },
+
+  onDeleteTempTableSuccess : function(){
+    console.log("onDeleteTempTableSuccess");
+    this.popUploadProgressInfos();
+    this.pushUploadProgressInfos("<li>Successfully inserted row. </li>");
+    this.onUploadSuccessfull();
+  },
+
+  onDeleteTempTableFailure : function(error){
+    console.log("onDeleteTempTableFailure");
+    this.setError(error);
+    this.setError("You will have to manually delete the table " + this.get("databaseName") + "." + this.get("tempTableName"));
+  },
+
+  createTableAndUploadFile : function(){
+    var self = this;
+    self.setError();
+    self.showUploadModal();
+    self.createActualTable()
+      .then(function(data){
+        console.log("1. received data : ", data);
+        return self.waitForCreateActualTable(data.jobId);
+      },function(error){
+        self.onCreateActualTableFailure(error);
+        console.log("Error occurred: ", error);
+        throw error;
+      })
+      .then(function(data){
+        console.log("2. received data : ", data);
+        self.onCreateActualTableSuccess(data);
+        return self.createTempTable(data);
+      },function(error){
+        if(!self.get('error')){
+          console.log("Error occurred: ", error);
+          self.onCreateActualTableFailure(new Error("Server job for creation of actual table failed."));
+        }
+        throw error;
+      })
+      .then(function(data){
+        console.log("3. received data : ", data);
+        return self.waitForCreateTempTable(data.jobId);
+      },function(error){
+        if(!self.get('error')){
+          console.log("Error occurred: ", error);
+          return self.onCreateTempTableFailure(error);
+        }
+        throw error;
+      })
+      .then(function(data){
+        console.log("4. received data : ", data);
+        self.onCreateTempTableSuccess(data);
+        return self.uploadFile(data);
+      },function(error){
+        if(!self.get('error')){
+          console.log("Error occurred: ", error);
+          return self.onCreateTempTableFailure(new Error("Server job for creation of temporary table failed."));
+        }
+        throw error;
+      }).then(function(data){
+        console.log("4.5 received data : ", data);
+        return self.waitForUploadingFile(data);
+      },function(error){
+        if(!self.get('error')){
+          console.log("Error occurred: ", error);
+          return self.onUploadingFileFailure(error);
+        }
+        throw error;
+      })
+      .then(function(data){
+        console.log("5. received data : ", data);
+        self.onUploadingFileSuccess(data);
+        return self.insertIntoTable(data);
+      },function(error){
+        if(!self.get('error')){
+          console.log("Error occurred: ", error);
+          return self.onUploadingFileFailure(new Error("Server job for upload of file failed."));
+        }
+        throw error;
+      })
+      .then(function(data){
+        console.log("6. received data : ", data);
+        return self.waitForInsertIntoTable(data.jobId);
+      },function(error){
+        if(!self.get('error')){
+          console.log("Error occurred: ", error);
+          return self.onInsertIntoTableFailure(error);
+        }
+        throw error;
+      })
+      .then(function(data){
+        console.log("7. received data : ", data);
+        self.onInsertIntoTableSuccess(data);
+        return self.deleteTempTable(data);
+      },function(error){
+        if(!self.get('error')){
+          console.log("Error occurred: ", error);
+          return self.onInsertIntoTableFailure(new Error("Server job for insert from temporary to actual table failed."));
+        }
+        throw error;
+      })
+      .then(function(data){
+        console.log("8. received data : ", data);
+        return self.waitForDeleteTempTable(data.jobId);
+      },function(error){
+        if(!self.get('error')){
+          console.log("Error occurred: ", error);
+          self.onDeleteTempTableFailure(error);
+        }
+        throw error;
+      })
+      .then(function(data){
+        console.log("9. received data : ", data);
+        self.onDeleteTempTableSuccess(data);
+      },function(error){
+        if(!self.get('error')){
+          console.log("Error occurred: ", error);
+          self.onDeleteTempTableFailure(new Error("Server job for deleting temporary table failed."));
+        }
+        throw error;
+      }).catch(function(error){
+        console.log("inside catch : ", error);
+      }).finally(function(){
+        console.log("finally hide the modal always");
+        self.hideUploadModal();
+      });
+  },
+
+  validateColumns: function () {
+    // throw exception if invalid.
+  },
+  setError: function (error) {
+    if(error){
+      console.log("upload table error : ", error);
+      this.set('error', JSON.stringify(error));
+      this.get('notifyService').error(error);
+    }else{
+      this.set("error");
+    }
+  },
+
+  previewError: function (error) {
+    this.setError(error);
+  },
+
+  uploadTableFromHdfs : function(){
+    console.log("uploadTableFromHdfs called.");
+    if(!(this.get("inputFileTypeCSV") == true && this.get("isFirstRowHeader") == false) ){
+      this.pushUploadProgressInfos("<li>Uploading file .... </li>");
+    }
+    return  this.get('uploader').uploadFromHDFS({
+        "isFirstRowHeader": this.get("isFirstRowHeader"),
+        "databaseName" :  this.get('databaseName'),
+        "tableName" : this.get("tempTableName"),
+        "inputFileType" : this.get("inputFileType").id,
+        "hdfsPath" : this.get("hdfsPath")
+      });
+  },
+  uploadTable: function () {
+    this.printValues();
+    return this.get('uploader').uploadFiles('upload', this.get('files'), {
+      "isFirstRowHeader": this.get("isFirstRowHeader"),
+      "databaseName" :  this.get('databaseName'),
+      "tableName" : this.get("tempTableName"),
+      "inputFileType" : this.get("inputFileType").id
+    });
+  },
+
+  onUploadSuccessfull: function (data) {
+    console.log("onUploadSuccessfull : ", data);
+    this.get('notifyService').success("Uploaded Successfully", "Table " + this.get('tableName') + " created in database " + this.get("databaseName"));
+    this.clearFields();
+  },
+
+  onUploadError: function (error) {
+    console.log("onUploadError : ", error);
+    this.setError(error);
+  },
+  showOrHide: function () {
+    if (this.get('show') == false) {
+      this.set("displayOption", "display:none");
+      this.set("showMoreOrLess", "Show More");
+    } else {
+      this.set("displayOption", "display:table-row");
+      this.set("showMoreOrLess", "Show Less");
+    }
+  },
+  displayOption: "display:none",
+  actions: {
+    toggleErrors: function () {
+      this.toggleProperty('showErrors');
+    },
+    filesUploaded: function (files) {
+      console.log("upload-table.js : uploaded new files : ", files);
+
+      this.clearFields();
+
+      this.set('files', files);
+      var name = files[0].name;
+      var i = name.indexOf(".");
+      var tableName = name.substr(0, i);
+      this.set('tableName', tableName);
+      var self = this;
+      return this.generatePreview(files)
+    },
+    previewFromHdfs : function(){
+      return this.generatePreview();
+    },
+    uploadTable : function(){
+      try{
+        this.createTableAndUploadFile();
+      }catch(e){
+        console.log("exception occured : ", e);
+        this.setError(e);
+        this.hideUploadModal();
+      }
+    },
+    uploadFromHDFS : function(){
+      this.set("isLocalUpload",false);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visual-explain.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visual-explain.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visual-explain.js
new file mode 100644
index 0000000..272aa11
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visual-explain.js
@@ -0,0 +1,64 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+  jobProgressService: Ember.inject.service(constants.namingConventions.jobProgress),
+  openQueries   : Ember.inject.controller(constants.namingConventions.openQueries),
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+
+  index: Ember.inject.controller(),
+  verticesProgress: Ember.computed.alias('jobProgressService.currentJob.stages'),
+
+  actions: {
+    onTabOpen: function () {
+      var self = this;
+
+      // Empty query
+      if(this.get('openQueries.currentQuery.fileContent').length == 0){
+        this.set('json', undefined);
+        this.set('noquery', 'hive.errors.no.query');
+        return;
+      } else {
+        this.set('noquery', undefined);
+      }
+      // Introducing a common function
+      var getVisualExplainJson = function(){
+        self.set('showSpinner', undefined);
+        self.set('rerender');
+        self.get('index')._executeQuery(constants.jobReferrer.visualExplain, true, true).then(function (json) {
+          //this condition should be changed once we change the way of retrieving this json
+          if (json['STAGE PLANS']['Stage-1']) {
+            self.set('json', json);
+          } else {
+            self.set('json', {})
+          }
+        }, function (error) {
+          self.set('json', undefined);
+          self.get('notifyService').error(error);
+        });
+        self.toggleProperty('shouldChangeGraph');
+      }
+
+      getVisualExplainJson();
+
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visualization-ui.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visualization-ui.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visualization-ui.js
new file mode 100644
index 0000000..c908afd
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/visualization-ui.js
@@ -0,0 +1,134 @@
+/**
+* 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.
+*/
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+  selectedRowCount: constants.defaultVisualizationRowCount,
+  needs: [ constants.namingConventions.index,
+            constants.namingConventions.openQueries,
+            constants.namingConventions.jobResults
+          ],
+  index         : Ember.computed.alias('controllers.' + constants.namingConventions.index),
+  openQueries   : Ember.computed.alias('controllers.' + constants.namingConventions.openQueries),
+  results   : Ember.computed.alias('controllers.' + constants.namingConventions.jobResults),
+  notifyService: Ember.inject.service(constants.namingConventions.notify),
+
+  polestarUrl: '',
+  voyagerUrl: '',
+  polestarPath: 'polestar/#/',
+  voyagerPath: 'voyager/#/',
+
+  showDataExplorer: true,
+  showAdvVisulization: false,
+
+  visualizationTabs: function () {
+    return [
+      Ember.Object.create({
+        name: 'Data Visualization',
+        id: 'visualization',
+        url: this.get('polestarUrl')
+      }),
+      Ember.Object.create({
+        name: 'Data Explorer',
+        id: 'data_explorer',
+        url: this.get('voyagerUrl')
+      })
+    ]
+  }.property('polestarUrl', 'voyagerUrl'),
+
+  activeTab: function () {
+    console.log("I am in activeTab function.");
+    this.get('visualizationTabs')[0].active = this.get("showDataExplorer");
+    this.get('visualizationTabs')[1].active = this.get("showAdvVisulization");
+  }.observes('polestarUrl', 'voyagerUrl'),
+
+  alterIframe: function () {
+    Ember.$("#visualization_frame").height(Ember.$("#visualization").height());
+  },
+
+  actions: {
+    onTabOpen: function () {
+      var self = this;
+      var model = this.get('index.model');
+      if (model) {
+        var existingJob = this.get('results').get('cachedResults').findBy('id', model.get('id'));
+        var url = this.container.lookup('adapter:application').buildURL();
+        url += '/' + constants.namingConventions.jobs + '/' + model.get('id') + '/results?&first=true';
+        url += '&count='+self.get('selectedRowCount')+'&job_id='+model.get('id')
+        if (existingJob) {
+          if(existingJob.results[0].rows.length === 0){
+            this.set("error", "Query has insufficient results to visualize the data.");
+            return;
+          }
+          this.set("error", null);
+          var id = model.get('id');
+          this.set("polestarUrl", this.get('polestarPath') + "?url=" + url);
+          this.set("voyagerUrl", this.get('voyagerPath') + "?url=" + url);
+          Ember.run.scheduleOnce('afterRender', this, function(){
+            self.alterIframe();
+          });
+        } else {
+          this.set("error", "No visualization available. Please execute a query and wait for the results to visualize the data.");
+        }
+      }
+    },
+
+      changeRowCount: function () {
+        var self = this;
+        if(isNaN(self.get('selectedRowCount')) || !(self.get('selectedRowCount')%1 === 0) || (self.get('selectedRowCount') <= 0)){
+          self.get('notifyService').error("Please enter a posive integer number.");
+          return;
+        }
+        var model = this.get('index.model');
+        if (model) {
+          var existingJob = this.get('results').get('cachedResults').findBy('id', model.get('id'));
+          var url = this.container.lookup('adapter:application').buildURL();
+          url += '/' + constants.namingConventions.jobs + '/' + model.get('id') + '/results?&first=true';
+          url += '&count='+self.get('selectedRowCount')+'&job_id='+model.get('id');
+          if (existingJob) {
+            this.set("error", null);
+            var id = model.get('id');
+
+            $('.nav-tabs.visualization-tabs li.active').each(function( index ) {
+
+              if($(this)[index].innerText.indexOf("Data Explorer") > -1){
+                self.set("showDataExplorer",true);
+                self.set("showAdvVisulization",false);
+                self.set("voyagerUrl", self.get('voyagerPath') + "?url=" + url);
+                self.set("polestarUrl", self.get('polestarPath') + "?url=" + url);
+                document.getElementById("visualization_frame").src =  self.get("voyagerUrl");
+              }
+              if($(this)[index].innerText.indexOf("Advanced Visualization") > -1){
+                self.set("showAdvVisulization",true);
+                self.set("showDataExplorer",false);
+                self.set("voyagerUrl", self.get('voyagerPath') + "?url=" + url);
+                self.set("polestarUrl", self.get('polestarPath') + "?url=" + url);
+                document.getElementById("visualization_frame").src = self.get("polestarUrl");
+              }
+            })
+            document.getElementById("visualization_frame").contentWindow.location.reload();
+          } else {
+            this.set("error", "No visualization available. Please execute a query and wait for the results to visualize data.");
+          }
+        }
+
+      }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js
new file mode 100644
index 0000000..92930a9
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/all-uppercase.js
@@ -0,0 +1,25 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export function allUppercase (input) {
+  return input ? input.toUpperCase() : input;
+}
+
+export default Ember.Handlebars.makeBoundHelper(allUppercase);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/code-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/code-helper.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/code-helper.js
new file mode 100644
index 0000000..8bbd19e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/code-helper.js
@@ -0,0 +1,28 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export function code (text) {
+  text = Ember.Handlebars.Utils.escapeExpression(text);
+  text = text.replace(/(\r\n|\n|\r)/gm, '<br>');
+
+  return new Ember.Handlebars.SafeString('<code>' + text + '</code>');
+}
+
+export default Ember.Handlebars.makeBoundHelper(code);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/date-binding.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/date-binding.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/date-binding.js
new file mode 100644
index 0000000..61251f8
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/date-binding.js
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+/* globals moment */
+
+import Ember from 'ember';
+
+export function pathBinding (data, key) {
+  return moment(data.get(key)).fromNow();
+}
+
+export default Ember.Handlebars.makeBoundHelper(pathBinding);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/format-column-type.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/format-column-type.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/format-column-type.js
new file mode 100644
index 0000000..13528b7
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/format-column-type.js
@@ -0,0 +1,39 @@
+/**
+ * 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.
+ */
+
+/**
+ used to format the precision and scale of type in database's table's columns
+**/
+
+import Ember from "ember";
+
+var columnTypeFormatter = function(column) {
+  var type = column.type;
+  var ext = type;
+  if( type === "VARCHAR" || type === "CHAR" || type == "DECIMAL"  ) {
+      ext += '(' + column.precision;
+    if (type == "DECIMAL") {
+        ext += "," + column.scale;
+    }
+    ext += ")";
+  }
+
+  return ext;
+};
+
+export default Ember.Handlebars.makeBoundHelper(columnTypeFormatter);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/log-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/log-helper.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/log-helper.js
new file mode 100644
index 0000000..c29d129
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/log-helper.js
@@ -0,0 +1,28 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export function log (text) {
+  text = Ember.Handlebars.Utils.escapeExpression(text);
+  text = text.replace(/(\r\n|\n|\r)/gm, '<br>');
+
+  return new Ember.Handlebars.SafeString(text);
+}
+
+export default Ember.Handlebars.makeBoundHelper(log);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/path-binding.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/path-binding.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/path-binding.js
new file mode 100644
index 0000000..926aaaa
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/path-binding.js
@@ -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.
+ */
+
+import Ember from 'ember';
+
+export function pathBinding (data, key) {
+  if (!data || !key) {
+    return;
+  }
+
+  return data.get ? data.get(key) : data[key];
+}
+
+export default Ember.Handlebars.makeBoundHelper(pathBinding);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/preformatted-string.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/preformatted-string.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/preformatted-string.js
new file mode 100644
index 0000000..4ab6a2e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/preformatted-string.js
@@ -0,0 +1,28 @@
+/**
+* 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.
+*/
+import Ember from 'ember';
+
+export function preformattedString (string) {
+  string = string.replace(/\\n/g, '&#10;'); // newline
+  string = string.replace(/\\t/g, '&#09;'); // tabs
+  string = string.replace(/^\s+|\s+$/g, ''); // trim
+
+  return new Ember.Handlebars.SafeString(string);
+}
+
+export default Ember.Handlebars.makeBoundHelper(preformattedString);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/tb-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/tb-helper.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/tb-helper.js
new file mode 100644
index 0000000..81af5ff
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/helpers/tb-helper.js
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+export function tb (key, data) {
+  var path = data.get ? data.get(key) : data[key];
+
+  if (!path && key) {
+    return Ember.I18n.t(key);
+  }
+
+  if (path) {
+    return Ember.I18n.t(path);
+  }
+}
+
+export default Ember.Handlebars.makeBoundHelper(tb);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/index.html
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/index.html b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/index.html
new file mode 100644
index 0000000..2cbf9f0
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/index.html
@@ -0,0 +1,42 @@
+<!--
+ * 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.
+-->
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title>Hive</title>
+    <meta name="description" content="">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    {{content-for 'head'}}
+
+    <link rel="stylesheet" href="assets/vendor.css">
+    <link rel="stylesheet" href="assets/hive.css">
+
+    {{content-for 'head-footer'}}
+  </head>
+  <body>
+    {{content-for 'body'}}
+
+    <script src="assets/vendor.js"></script>
+    <script src="assets/hive.js"></script>
+
+    {{content-for 'body-footer'}}
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js
new file mode 100644
index 0000000..b3630c1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js
@@ -0,0 +1,269 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+var TRANSLATIONS;
+
+export default {
+  name: 'i18n',
+  initialize: function () {
+    Ember.ENV.I18N_COMPILE_WITHOUT_HANDLEBARS = true;
+    Ember.FEATURES.I18N_TRANSLATE_HELPER_SPAN = false;
+    Ember.I18n.translations = TRANSLATIONS;
+    Ember.TextField.reopen(Ember.I18n.TranslateableAttributes);
+  }
+};
+
+TRANSLATIONS = {
+  tooltips: {
+    refresh: 'Refresh database',
+    loadSample: 'Load sample data',
+    query: 'Query',
+    settings: 'Settings',
+    visualExplain: 'Visual Explain',
+    tez: 'Tez',
+    visualization: 'Visualization',
+    notifications: 'Notifications',
+    expand: 'Expand query panel',
+    makeSettingGlobal: 'Make setting global',
+    overwriteGlobalValue: 'Overwrite global setting value'
+  },
+
+  alerts: {
+    errors: {
+      save: {
+        query: "Error when trying to execute the query",
+        results: "Error when trying to save the results."
+      },
+      get: {
+        tables: 'Error when trying to retrieve the tables for the selected database',
+        columns: 'Error when trying to retrieve the table columns.'
+      },
+      sessions: {
+        delete: 'Error invalidating sessions'
+      },
+      job: {
+        status: "An error occured while processing the job."
+      }
+    },
+    success: {
+      sessions: {
+        deleted: 'Session invalidated.'
+      },
+      settings: {
+        saved: 'Settings have been saved.'
+      },
+      query: {
+        execution: 'Query has been submitted.',
+        save: 'The query has been saved.',
+        update: 'The query has been updated.'
+      }
+    }
+  },
+
+  modals: {
+    delete: {
+      heading: 'Confirm deletion',
+      message: 'Are you sure you want to delete this item?',
+      emptyQueryMessage: "Your query is empty. Do you want to delete this item?"
+    },
+
+    save: {
+      heading: 'Saving item',
+      saveBeforeCloseHeading: "Save item before closing?",
+      message: 'Enter name:',
+      overwrite: 'Saving will overwrite previously saved query'
+    },
+
+    download: {
+      csv: 'Download results as CSV',
+      hdfs: 'Please enter save path and name'
+    },
+
+    changeTitle: {
+      heading: 'Rename worksheet'
+    },
+    authenticationLDAP: {
+       heading: 'Enter the LDAP password'
+    }
+  },
+
+  titles: {
+    database: 'Database Explorer',
+    explorer: 'Databases',
+    results: 'Search Results',
+    settings: 'Database Settings',
+    query: {
+      tab: 'Worksheet',
+      editor: 'Query Editor',
+      process: 'Query Process Results',
+      parameters: 'Parameters',
+      visualExplain: 'Visual Explain',
+      tez: 'TEZ',
+      status: 'Status: ',
+      messages: 'Messages',
+      visualization: 'Visualization'
+    },
+    download: 'Save results...',
+    tableSample: '{{tableName}} sample'
+  },
+
+  placeholders: {
+    search: {
+      tables: 'Search tables...',
+      columns: 'Search columns in result tables...',
+      results: 'Filter columns...'
+    },
+    select: {
+      database: 'Select Database...',
+      udfs: 'Insert udfs',
+      file: 'Select File Resource...',
+      noFileResource: '(no file)',
+      value: "Select value..."
+    },
+    fileResource: {
+      name: "resource name",
+      path: "resource path"
+    },
+    udfs: {
+      name: 'udf name',
+      className: 'udf class name',
+      path: "resource path",
+      database: 'Select Database...'
+    },
+    settings: {
+      key: 'mapred.reduce.tasks',
+      value: '1'
+    }
+  },
+
+  menus: {
+    query: 'Query',
+    savedQueries: 'Saved Queries',
+    history: 'History',
+    udfs: 'UDFs',
+    uploadTable: 'Upload Table',
+    logs: 'Logs',
+    results: 'Results',
+    explain: 'Explain'
+  },
+
+  columns: {
+    id: 'id',
+    shortQuery: 'preview',
+    fileResource: 'file resource',
+    title: 'title',
+    database: 'database',
+    owner: 'owner',
+    user: 'user',
+    date: 'date submitted',
+    duration: 'duration',
+    status: 'status',
+    expand: '',
+    actions: ''
+  },
+
+  buttons: {
+    addItem: 'Add new item...',
+    insert: 'Insert',
+    delete: 'Delete',
+    cancel: 'Cancel',
+    edit: 'Edit',
+    execute: 'Execute',
+    explain: 'Explain',
+    saveAs: 'Save as...',
+    save: 'Save',
+    newQuery: 'New Worksheet',
+    newUdf: 'New UDF',
+    history: 'History',
+    ok: 'OK',
+    stopJob: 'Stop execution',
+    stoppingJob: 'Stopping...',
+    close: 'Close',
+    clearFilters: 'Clear filters',
+    expand: 'Expand message',
+    collapse: 'Collapse message',
+    previousPage: 'previous',
+    uploadTable: 'Upload Table',
+    showPreview: 'Preview',
+    nextPage: 'next',
+    loadMore: 'Load more...',
+    saveHdfs: 'Save to HDFS',
+    saveCsv: 'Download as CSV',
+    runOnTez: 'Run on Tez',
+    killSession: 'Kill Session'
+  },
+
+  labels: {
+    noTablesMatch: 'No tables match',
+    table: 'Table ',
+    hoursShort: "{{hours}} hrs",
+    minsShort: "{{minutes}} mins",
+    secsShort: "{{seconds}} secs"
+  },
+
+  popover: {
+    visualExplain: {
+      statistics: "Statistics"
+    },
+    queryEditorHelp: {
+      title: "Did you know?",
+      content: {
+        line1: "Press CTRL + Space to autocomplete",
+        line2: "You can execute queries with multiple SQL statements delimited by a semicolon ';'",
+        line3: "You can highlight and run a fragment of a query"
+      }
+    },
+    add: 'Add'
+  },
+
+  tez: {
+    errors: {
+      'not.deployed': "Tez View isn't deployed.",
+      'no.instance': "No instance of Tez View found.",
+      'no.dag': "No DAG available"
+    }
+  },
+
+  hive: {
+    errors: {
+      'no.query': "No query to process.",
+      'emptyDatabase' : "Please select Database.",
+      'emptyTableName' : "Please enter tableName.",
+      'emptyIsFirstRow' : "Please select is First Row Header?"
+    }
+  },
+
+  emptyList: {
+    history: {
+      noItems: "No queries were run.",
+      noMatches: "No jobs match your filtering criteria",
+    },
+    savedQueries: {
+      noItems: "No queries were saved.",
+      noMatches: "No queries match your filtering criteria"
+    }
+  },
+
+  settings: {
+    parsed: "Query settings added"
+  },
+
+  generalError: 'Unexpected error'
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/app/mixins/filterable.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/mixins/filterable.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/mixins/filterable.js
new file mode 100644
index 0000000..aa1f4cd
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/mixins/filterable.js
@@ -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.
+ */
+
+import Ember from 'ember';
+import utils from 'hive/utils/functions';
+
+export default Ember.Mixin.create({
+  init: function () {
+    this._super();
+    this.clearFilters();
+  },
+
+  filter: function (items) {
+    var self = this;
+
+    if (items && this.get('filters.length')) {
+      items = items.filter(function (item) {
+        return self.get('filters').every(function (filter) {
+          var propValue = item.get(filter.property);
+
+          if (!!filter.value) {
+            if (filter.min !== undefined && filter.max !== undefined) {
+              if (utils.isInteger(propValue)) {
+                return +propValue >= +filter.min && +propValue <= +filter.max;
+              } else if (utils.isDate(propValue)) {
+                return propValue >= filter.min && propValue <= filter.max;
+              } else {
+                return false;
+              }
+            } else if (filter.exactMatch) {
+              return propValue == filter.value;
+            } else {
+              return propValue && propValue.toLowerCase().indexOf(filter.value.toLowerCase()) > -1;
+            }
+          }
+
+          return false;
+        });
+      });
+    }
+
+    return items;
+  },
+
+  updateFilters: function (property, filterValue, exactMatch) {
+    var addFilter = function () {
+      if (!filterValue) {
+        return;
+      }
+
+      this.get('filters').pushObject(Ember.Object.create({
+        property: property,
+        exactMatch: exactMatch,
+        min: filterValue.min,
+        max: filterValue.max,
+        value: filterValue
+      }));
+    };
+
+    var existentFilter = this.get('filters').find(function (filter) {
+      return filter.property === property;
+    });
+
+    if (existentFilter) {
+      if (filterValue) {
+        //remove and add again for triggering collection change thus avoiding to add observers on individual properties of a filter
+        this.get('filters').removeObject(existentFilter);
+        addFilter.apply(this);
+      } else {
+        //ensures removal of the filterValue when it's an empty string
+        this.set('filters', this.get('filters').without(existentFilter));
+      }
+    } else {
+       addFilter.apply(this);
+    }
+  },
+
+  clearFilters: function () {
+    var filters = this.get('filters');
+
+    if (!filters || filters.get('length')) {
+      this.set('filters', Ember.A());
+    }
+  },
+
+  actions: {
+    filter: function (property, filterValue) {
+      this.updateFilters(property, filterValue);
+    }
+  }
+});


[28/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

Posted by jl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
index c7738cd..d3e549f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
@@ -29,6 +29,9 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.AmbariServer;
 import org.apache.ambari.server.controller.StackVersionResponse;
 import org.apache.ambari.server.stack.Validable;
 import org.apache.ambari.server.state.repository.VersionDefinitionXml;
@@ -146,13 +149,40 @@ public class StackInfo implements Comparable<StackInfo>, Validable{
     return services;
   }
 
-  public ServiceInfo getService(String name) {
+  public ServiceInfo getService(String serviceName) {
     Collection<ServiceInfo> services = getServices();
     for (ServiceInfo service : services) {
-      if (service.getName().equals(name)) {
+      if (service.getName().equals(serviceName)) {
         return service;
       }
     }
+
+    // HACK: If service name is different from stack service name, try using stack service name
+    try {
+      AmbariManagementController controller = AmbariServer.getController();
+      if (controller != null) {
+        Clusters clusters = controller.getClusters();
+        Map<String, Cluster> clusterMap = clusters.getClusters();
+        if (clusterMap != null && clusterMap.size() != 0) {
+          for (Cluster c : clusterMap.values()) {
+            StackId stackId = c.getCurrentStackVersion();
+            if (stackId.getStackName().equalsIgnoreCase(getName()) && stackId.getStackVersion().equalsIgnoreCase(version)) {
+              Service svc = c.getService(serviceName);
+              if (svc != null) {
+                String stackServiceName = svc.getStackServiceName();
+                for (ServiceInfo service : services) {
+                  if (service.getName().equals(stackServiceName)) {
+                    return service;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    } catch (AmbariException e) {
+
+    }
     //todo: exception?
     return null;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index 6cf9933..c8a3e72 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -38,6 +38,7 @@ import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import javax.annotation.Nullable;
+import javax.annotation.OverridingMethodsMustInvokeSuper;
 import javax.persistence.EntityManager;
 import javax.persistence.RollbackException;
 
@@ -49,6 +50,7 @@ import org.apache.ambari.server.ParentObjectNotFoundException;
 import org.apache.ambari.server.ServiceComponentHostNotFoundException;
 import org.apache.ambari.server.ServiceComponentNotFoundException;
 import org.apache.ambari.server.ServiceNotFoundException;
+import org.apache.ambari.server.ServiceGroupNotFoundException;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
@@ -83,6 +85,7 @@ import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
 import org.apache.ambari.server.orm.entities.ClusterConfigMappingEntity;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
+import org.apache.ambari.server.orm.entities.ClusterServiceGroupEntity;
 import org.apache.ambari.server.orm.entities.ClusterStateEntity;
 import org.apache.ambari.server.orm.entities.ClusterVersionEntity;
 import org.apache.ambari.server.orm.entities.ConfigGroupEntity;
@@ -103,31 +106,7 @@ import org.apache.ambari.server.orm.entities.UpgradeGroupEntity;
 import org.apache.ambari.server.orm.entities.UpgradeItemEntity;
 import org.apache.ambari.server.security.authorization.AuthorizationException;
 import org.apache.ambari.server.security.authorization.AuthorizationHelper;
-import org.apache.ambari.server.state.Cluster;
-import org.apache.ambari.server.state.ClusterHealthReport;
-import org.apache.ambari.server.state.Clusters;
-import org.apache.ambari.server.state.ComponentInfo;
-import org.apache.ambari.server.state.Config;
-import org.apache.ambari.server.state.ConfigFactory;
-import org.apache.ambari.server.state.ConfigHelper;
-import org.apache.ambari.server.state.DesiredConfig;
-import org.apache.ambari.server.state.Host;
-import org.apache.ambari.server.state.HostHealthStatus;
-import org.apache.ambari.server.state.HostState;
-import org.apache.ambari.server.state.MaintenanceState;
-import org.apache.ambari.server.state.PropertyInfo;
-import org.apache.ambari.server.state.RepositoryVersionState;
-import org.apache.ambari.server.state.SecurityType;
-import org.apache.ambari.server.state.Service;
-import org.apache.ambari.server.state.ServiceComponent;
-import org.apache.ambari.server.state.ServiceComponentHost;
-import org.apache.ambari.server.state.ServiceComponentHostEvent;
-import org.apache.ambari.server.state.ServiceComponentHostEventType;
-import org.apache.ambari.server.state.ServiceFactory;
-import org.apache.ambari.server.state.ServiceInfo;
-import org.apache.ambari.server.state.StackId;
-import org.apache.ambari.server.state.StackInfo;
-import org.apache.ambari.server.state.State;
+import org.apache.ambari.server.state.*;
 import org.apache.ambari.server.state.configgroup.ConfigGroup;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
@@ -174,6 +153,8 @@ public class ClusterImpl implements Cluster {
 
   private volatile Map<String, Service> services = null;
 
+  private volatile Map<String, ServiceGroup> serviceGroups = null;
+
   /**
    * [ Config Type -> [ Config Version Tag -> Config ] ]
    */
@@ -234,6 +215,9 @@ public class ClusterImpl implements Cluster {
   private ServiceFactory serviceFactory;
 
   @Inject
+  private ServiceGroupFactory serviceGroupFactory;
+
+  @Inject
   private ConfigFactory configFactory;
 
   @Inject
@@ -362,7 +346,15 @@ public class ClusterImpl implements Cluster {
       ServiceInfo serviceInfo = entry.getValue();
       Set<String> configTypes = serviceInfo.getConfigTypeAttributes().keySet();
       for (String configType : configTypes) {
-        serviceConfigTypes.put(serviceName, configType);
+        String configValue = configType + "," + configType;
+        serviceConfigTypes.put(serviceName, configValue);
+        // HACK : JRL : Create static service config mappings for service instances
+        for(int i = 1; i<= 5; i++) {
+          String serviceInstanceName = serviceName.concat("-" + i);
+          String instanceConfigType = configType.concat("-" + i);
+          configValue = instanceConfigType + "," + configType;
+          serviceConfigTypes.put(serviceInstanceName, configValue);
+        }
       }
     }
 
@@ -443,15 +435,15 @@ public class ClusterImpl implements Cluster {
                 StackId stackId = getCurrentStackVersion();
                 try {
                   if (ambariMetaInfo.getService(stackId.getStackName(),
-                    stackId.getStackVersion(), serviceEntity.getServiceName()) != null) {
+                    stackId.getStackVersion(), serviceEntity.getStackServiceName()) != null) {
                     services.put(serviceEntity.getServiceName(),
                       serviceFactory.createExisting(this, serviceEntity));
                   }
                 } catch (AmbariException e) {
                   LOG.error(String.format(
-                    "Can not get service info: stackName=%s, stackVersion=%s, serviceName=%s",
+                    "Can not get service info: stackName=%s, stackVersion=%s, serviceName=%s, stackServiceName=%s",
                     stackId.getStackName(), stackId.getStackVersion(),
-                    serviceEntity.getServiceName()));
+                    serviceEntity.getServiceName(), serviceEntity.getStackServiceName()));
                 }
               }
             }
@@ -463,6 +455,31 @@ public class ClusterImpl implements Cluster {
     }
   }
 
+  private void loadServiceGroups() {
+    if (serviceGroups == null) {
+      clusterGlobalLock.writeLock().lock();
+
+      try {
+        if (serviceGroups == null) {
+          ClusterEntity clusterEntity = getClusterEntity();
+          if (clusterEntity != null) {
+            serviceGroups = new TreeMap<String, ServiceGroup>();
+
+            if (!clusterEntity.getClusterServiceGroupEntities().isEmpty()) {
+              for (ClusterServiceGroupEntity serviceGroupEntity : clusterEntity.getClusterServiceGroupEntities()) {
+                serviceGroups.put(serviceGroupEntity.getServiceGroupName(),
+                    serviceGroupFactory.createExisting(this, serviceGroupEntity));
+
+              }
+            }
+          }
+        }
+      } finally {
+        clusterGlobalLock.writeLock().unlock();
+      }
+    }
+  }
+
   private void loadConfigGroups() {
     if (clusterConfigGroups == null) {
       clusterGlobalLock.writeLock().lock();
@@ -988,7 +1005,7 @@ public class ClusterImpl implements Cluster {
       if (LOG.isDebugEnabled()) {
         LOG.debug("Adding a new Service" + ", clusterName=" + getClusterName()
           + ", clusterId=" + getClusterId() + ", serviceName="
-          + service.getName());
+          + service.getName() + ", stackServiceName=" + service.getStackServiceName());
       }
       services.put(service.getName(), service);
     } finally {
@@ -997,20 +1014,20 @@ public class ClusterImpl implements Cluster {
   }
 
   @Override
-  public Service addService(String serviceName) throws AmbariException {
+  public Service addService(String serviceName, String stackServiceName, String serviceGroupName) throws AmbariException {
     loadServices();
     clusterGlobalLock.writeLock().lock();
     try {
       if (LOG.isDebugEnabled()) {
         LOG.debug("Adding a new Service" + ", clusterName=" + getClusterName()
-          + ", clusterId=" + getClusterId() + ", serviceName=" + serviceName);
+          + ", clusterId=" + getClusterId() + ", serviceName=" + serviceName + ", stackServiceName=" + stackServiceName);
       }
       if (services.containsKey(serviceName)) {
         throw new AmbariException("Service already exists" + ", clusterName="
             + getClusterName() + ", clusterId=" + getClusterId()
-            + ", serviceName=" + serviceName);
+            + ", serviceName=" + serviceName + ", stackServiceName=" + stackServiceName);
       }
-      Service s = serviceFactory.createNew(this, serviceName);
+      Service s = serviceFactory.createNew(this, serviceName, stackServiceName, serviceGroupName);
       services.put(s.getName(), s);
       return s;
     } finally {
@@ -1019,6 +1036,22 @@ public class ClusterImpl implements Cluster {
   }
 
   @Override
+  public void addServiceGroup(ServiceGroup serviceGroup) {
+    loadServices();
+    clusterGlobalLock.writeLock().lock();
+    try {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Adding a new service group" + ", clusterName=" + getClusterName()
+            + ", clusterId=" + getClusterId() + ", serviceGroupName="
+            + serviceGroup.getName());
+      }
+      serviceGroups.put(serviceGroup.getName(), serviceGroup);
+    } finally {
+      clusterGlobalLock.writeLock().unlock();
+    }
+  }
+
+  @Override
   public Service getService(String serviceName) throws AmbariException {
     loadServices();
     clusterGlobalLock.readLock().lock();
@@ -1044,6 +1077,31 @@ public class ClusterImpl implements Cluster {
   }
 
   @Override
+  public ServiceGroup getServiceGroup(String serviceGroupName) throws ServiceGroupNotFoundException {
+    loadServiceGroups();
+    clusterGlobalLock.readLock().lock();
+    try {
+      if (!serviceGroups.containsKey(serviceGroupName)) {
+        throw new ServiceGroupNotFoundException(getClusterName(), serviceGroupName);
+      }
+      return serviceGroups.get(serviceGroupName);
+    } finally {
+      clusterGlobalLock.readLock().unlock();
+    }
+  }
+
+  @Override
+  public Map<String, ServiceGroup> getServiceGroups() throws AmbariException {
+    loadServiceGroups();
+    clusterGlobalLock.readLock().lock();
+    try {
+      return new HashMap<>(serviceGroups);
+    } finally {
+      clusterGlobalLock.readLock().unlock();
+    }
+  }
+
+  @Override
   public StackId getDesiredStackVersion() {
     loadStackVersion();
     clusterGlobalLock.readLock().lock();
@@ -2226,6 +2284,33 @@ public class ClusterImpl implements Cluster {
     }
   }
 
+  @Override
+  public void deleteAllServiceGroups() throws AmbariException {
+
+  }
+
+  @Override
+  public void deleteServiceGroup(String serviceGroupName) throws AmbariException {
+    loadServiceGroups();
+    clusterGlobalLock.writeLock().lock();
+    try {
+      ServiceGroup serviceGroup = getServiceGroup(serviceGroupName);
+      LOG.info("Deleting service group for cluster" + ", clusterName="
+          + getClusterName() + ", serviceGroupName=" + serviceGroup.getName());
+      // FIXME check dependencies from meta layer
+      if (!serviceGroup.canBeRemoved()) {
+        throw new AmbariException("Could not delete service group from cluster"
+            + ", clusterName=" + getClusterName()
+            + ", serviceGroupName=" + serviceGroup.getName());
+      }
+      deleteServiceGroup(serviceGroup);
+      serviceGroups.remove(serviceGroupName);
+
+    } finally {
+      clusterGlobalLock.writeLock().unlock();
+    }
+  }
+
   /**
    * Deletes the specified service also removes references to it from {@link this.serviceComponentHosts}
    * and references to ServiceComponentHost objects that belong to the service from {@link this.serviceComponentHostsByHost}
@@ -2253,6 +2338,21 @@ public class ClusterImpl implements Cluster {
     }
   }
 
+  /**
+   * Deletes the specified service also removes references to it from {@link this.serviceComponentHosts}
+   * and references to ServiceComponentHost objects that belong to the service from {@link this.serviceComponentHostsByHost}
+   * <p>
+   *   Note: This method must be called only with write lock acquired.
+   * </p>
+   * @param serviceGroup the service group to be deleted
+   * @throws AmbariException
+   * @see   ServiceComponentHost
+   */
+  private void deleteServiceGroup(ServiceGroup serviceGroup) throws AmbariException {
+    final String serviceGroupName = serviceGroup.getName();
+    serviceGroup.delete();
+  }
+
   @Override
   public boolean canBeRemoved() {
     loadServices();
@@ -2524,7 +2624,11 @@ public class ClusterImpl implements Cluster {
     String serviceName = null;
     for (String configType : configTypes) {
       for (Entry<String, String> entry : serviceConfigTypes.entries()) {
-        if (StringUtils.equals(entry.getValue(), configType)) {
+        String value = entry.getValue();
+        String values[] = value.split(",");
+        String instanceConfigType = values[0];
+        String stackConfigType = values[1];
+        if (StringUtils.equals(instanceConfigType, configType)) {
           if (serviceName != null) {
             if (entry.getKey()!=null && !StringUtils.equals(serviceName, entry.getKey())) {
               throw new IllegalArgumentException(String.format("Config type %s belongs to %s service, " +
@@ -2544,8 +2648,12 @@ public class ClusterImpl implements Cluster {
   public String getServiceByConfigType(String configType) {
     for (Entry<String, String> entry : serviceConfigTypes.entries()) {
       String serviceName = entry.getKey();
-      String type = entry.getValue();
-      if (StringUtils.equals(type, configType)) {
+      String value = entry.getValue();
+      String values[] = value.split(",");
+      String instanceConfigType = values[0];
+      String stackConfigType = values[1];
+
+      if (StringUtils.equals(instanceConfigType, configType)) {
         return serviceName;
       }
     }
@@ -2553,6 +2661,22 @@ public class ClusterImpl implements Cluster {
   }
 
   @Override
+  public String getStackConfigTypeFromConfigType(String configType) {
+    for (Entry<String, String> entry : serviceConfigTypes.entries()) {
+      String serviceName = entry.getKey();
+      String value = entry.getValue();
+      String values[] = value.split(",");
+      String instanceConfigType = values[0];
+      String stackConfigType = values[1];
+
+      if (StringUtils.equals(instanceConfigType, configType)) {
+        return stackConfigType;
+      }
+    }
+    return null;
+  }
+
+  @Override
   public ServiceConfigVersionResponse setServiceConfigVersion(String serviceName, Long version, String user, String note) throws AmbariException {
     if (null == user) {
       throw new NullPointerException("User must be specified.");
@@ -2740,9 +2864,14 @@ public class ClusterImpl implements Cluster {
       List<ClusterConfigMappingEntity> mappingEntities =
           clusterDAO.getClusterConfigMappingEntitiesByCluster(getClusterId());
       for (ClusterConfigMappingEntity entity : mappingEntities) {
-        if (configTypes.contains(entity.getType()) && entity.isSelected() > 0) {
-          entity.setSelected(0);
-          entity = clusterDAO.mergeConfigMapping(entity);
+        for(String configType : configTypes) {
+          String values[] = configType.split(",");
+          String instanceConfigType = values[0];
+          String stackConfigType = values[1];
+          if (StringUtils.equals(instanceConfigType, entity.getType()) && entity.isSelected() > 0) {
+            entity.setSelected(0);
+            entity = clusterDAO.mergeConfigMapping(entity);
+          }
         }
       }
 
@@ -2834,7 +2963,11 @@ public class ClusterImpl implements Cluster {
     String serviceName = null;
     for (Config config : configs) {
       for (Entry<String, String> entry : serviceConfigTypes.entries()) {
-        if (StringUtils.equals(entry.getValue(), config.getType())) {
+        String value = entry.getValue();
+        String values[] = value.split(",");
+        String instanceConfigType = values[0];
+        String stackConfigType = values[1];
+        if (StringUtils.equals(instanceConfigType, config.getType())) {
           if (serviceName == null) {
             serviceName = entry.getKey();
             break;
@@ -2881,14 +3014,19 @@ public class ClusterImpl implements Cluster {
     //add configs from this service
     Collection<String> configTypes = serviceConfigTypes.get(serviceName);
     for (ClusterConfigMappingEntity mappingEntity : clusterDAO.getClusterConfigMappingEntitiesByCluster(getClusterId())) {
-      if (mappingEntity.isSelected() > 0 && configTypes.contains(mappingEntity.getType())) {
-        ClusterConfigEntity configEntity =
-          clusterDAO.findConfig(getClusterId(), mappingEntity.getType(), mappingEntity.getTag());
-        if (configEntity != null) {
-          configEntities.add(configEntity);
-        } else {
-          LOG.error("Desired cluster config type={}, tag={} is not present in database," +
-            " unable to add to service config version");
+      for(String configType : configTypes) {
+        String values[] = configType.split(",");
+        String instanceConfigType = values[0];
+        String stackConfigType = values[1];
+        if (mappingEntity.isSelected() > 0 && StringUtils.equals(instanceConfigType, mappingEntity.getType())) {
+          ClusterConfigEntity configEntity =
+              clusterDAO.findConfig(getClusterId(), mappingEntity.getType(), mappingEntity.getTag());
+          if (configEntity != null) {
+            configEntities.add(configEntity);
+          } else {
+            LOG.error("Desired cluster config type={}, tag={} is not present in database," +
+                " unable to add to service config version");
+          }
         }
       }
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
index f78dd95..c26e1e9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
@@ -297,6 +297,22 @@ public class ClustersImpl implements Clusters {
   }
 
   @Override
+  public Cluster getCluster(Long clusterId)
+    throws AmbariException {
+    checkLoaded();
+
+    Cluster cluster = null;
+    if (clusterId != null) {
+      cluster = clustersById.get(clusterId);
+    }
+    if (null == cluster) {
+      throw new ClusterNotFoundException(clusterId);
+    }
+    RetryHelper.addAffectedCluster(cluster);
+    return cluster;
+  }
+
+  @Override
   public Cluster getClusterById(long id) throws AmbariException {
     checkLoaded();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupImpl.java
index 1d6b1e8..cc0dd36 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/configgroup/ConfigGroupImpl.java
@@ -419,6 +419,7 @@ public class ConfigGroupImpl implements ConfigGroup {
           clusterConfigEntity.setClusterEntity(clusterEntity);
           clusterConfigEntity.setStack(clusterEntity.getDesiredStack());
           clusterConfigEntity.setType(config.getType());
+          clusterConfigEntity.setStackType(config.getStackType());
           clusterConfigEntity.setVersion(config.getVersion());
           clusterConfigEntity.setTag(config.getTag());
           clusterConfigEntity.setData(gson.toJson(config.getProperties()));

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
index feae6e5..3fe59ca 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
@@ -1158,6 +1158,17 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
   }
 
   @Override
+  public String getStackServiceName() {
+    return serviceComponent.getStackServiceName();
+  }
+
+  @Override
+  public String getServiceGroupName() {
+    return serviceComponent.getServiceGroupName();
+  }
+
+
+  @Override
   public StackId getStackVersion() {
     readLock.lock();
     try {
@@ -1453,7 +1464,7 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
 
           ServiceComponentInstalledEvent event = new ServiceComponentInstalledEvent(
               getClusterId(), stackId.getStackName(),
-              stackId.getStackVersion(), getServiceName(), getServiceComponentName(), getHostName(),
+              stackId.getStackVersion(), getServiceName(), getStackServiceName(), getServiceGroupName(), getServiceComponentName(), getHostName(),
                   isRecoveryEnabled());
 
           eventPublisher.publish(event);
@@ -1597,12 +1608,14 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
       String stackVersion = stackId.getStackVersion();
       String stackName = stackId.getStackName();
       String serviceName = getServiceName();
+      String stackServiceName = getStackServiceName();
+      String serviceGroupName = getServiceGroupName();
       String componentName = getServiceComponentName();
       String hostName = getHostName();
       boolean recoveryEnabled = isRecoveryEnabled();
 
       ServiceComponentUninstalledEvent event = new ServiceComponentUninstalledEvent(
-          clusterId, stackName, stackVersion, serviceName, componentName,
+          clusterId, stackName, stackVersion, serviceName, stackServiceName, serviceGroupName, componentName,
           hostName, recoveryEnabled);
 
       eventPublisher.publish(event);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
index e3b51c0..e40b3ae 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
@@ -194,10 +194,10 @@ public class AmbariContext {
     Set<ServiceRequest> serviceRequests = new HashSet<ServiceRequest>();
     Set<ServiceComponentRequest> componentRequests = new HashSet<ServiceComponentRequest>();
     for (String service : services) {
-      serviceRequests.add(new ServiceRequest(clusterName, service, null));
+      serviceRequests.add(new ServiceRequest(clusterName, service, service, "CORE", null));
       for (String component : topology.getBlueprint().getComponents(service)) {
         String recoveryEnabled = String.valueOf(topology.getBlueprint().isRecoveryEnabled(service, component));
-        componentRequests.add(new ServiceComponentRequest(clusterName, service, component, null, recoveryEnabled));
+        componentRequests.add(new ServiceComponentRequest(clusterName, service, component, null, null, recoveryEnabled));
       }
     }
     try {

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog150.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog150.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog150.java
index ff94795..d63373c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog150.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog150.java
@@ -717,11 +717,13 @@ public class UpgradeCatalog150 extends AbstractUpgradeCatalog {
       List<ClusterServiceEntity> clusterServiceEntities = clusterServiceDAO.findAll();
       for (final ClusterServiceEntity clusterServiceEntity : clusterServiceEntities) {
         String serviceName = clusterServiceEntity.getServiceName();
+        String stackServiceName = clusterServiceEntity.getStackServiceName();
+        String serviceGroupName = clusterServiceEntity.getServiceGroupName();
         ServiceInfo serviceInfo = null;
         try {
-          serviceInfo = ambariMetaInfo.getService(stackName, stackVersion, serviceName);
+          serviceInfo = ambariMetaInfo.getService(stackName, stackVersion, stackServiceName);
         } catch (AmbariException e) {
-          LOG.error("Service " + serviceName + " not found for " + stackName + stackVersion);
+          LOG.error("Service " + stackServiceName + " not found for " + stackName + " " + stackVersion + " " + serviceName);
           continue;
         }
         List<String> configTypes = serviceInfo.getConfigDependencies();
@@ -812,6 +814,7 @@ public class UpgradeCatalog150 extends AbstractUpgradeCatalog {
                       HostComponentDesiredStateEntityPK entityPK =
                         new HostComponentDesiredStateEntityPK();
                       entityPK.setClusterId(clusterId);
+                      // TODO: JRL Hardcoded service names :(
                       entityPK.setServiceName("HDFS");
                       entityPK.setComponentName("DATANODE");
                       entityPK.setHostId(hostEntity.getHostId());

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
index 41f538e..01b72d1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
@@ -131,6 +131,7 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
   public static final String BLUEPRINT_TABLE = "blueprint";
   public static final String VIEWINSTANCE_TABLE = "viewinstance";
   public static final String SHORT_URL_COLUMN = "short_url";
+  public static final String CLUSTER_HANDLE_COLUMN = "cluster_handle";
   protected static final String CLUSTER_VERSION_TABLE = "cluster_version";
   protected static final String HOST_VERSION_TABLE = "host_version";
 
@@ -246,6 +247,7 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
     createViewUrlTableDDL();
     updateViewInstanceEntityTable();
     createRemoteClusterTable();
+    updateViewInstanceTable();
   }
 
   private void createRemoteClusterTable() throws SQLException {
@@ -341,7 +343,7 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
 
   private void insertClusterInheritedPrincipal(String name) {
     PrincipalTypeEntity principalTypeEntity = new PrincipalTypeEntity();
-    principalTypeEntity.setName("ALL.CLUSTER.ADMINISTRATOR");
+    principalTypeEntity.setName(name);
     principalTypeEntity = principalTypeDAO.merge(principalTypeEntity);
 
     PrincipalEntity principalEntity = new PrincipalEntity();
@@ -2017,4 +2019,55 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
   private void updateTezViewProperty() throws SQLException {
     dbAccessor.executeUpdate("UPDATE viewinstanceproperty SET name = 'yarn.ats.url' where name = 'yarn.timeline-server.url'");
   }
+
+  /**
+   *  Update view instance table's cluster_handle column to have cluster_id
+   *  instead of cluster_name
+   */
+  @Transactional
+  private void updateViewInstanceTable() throws SQLException {
+    try {
+      if (Long.class.equals(dbAccessor.getColumnClass(VIEWINSTANCE_TABLE, CLUSTER_HANDLE_COLUMN))) {
+        LOG.info(String.format("%s column is already numeric. Skipping an update of %s table.", CLUSTER_HANDLE_COLUMN, VIEWINSTANCE_TABLE));
+        return;
+      }
+    } catch (ClassNotFoundException e) {
+      LOG.warn("Cannot determine a type of " + CLUSTER_HANDLE_COLUMN + " column.");
+    }
+
+    String cluster_handle_dummy = "cluster_handle_dummy";
+
+    dbAccessor.addColumn(VIEWINSTANCE_TABLE,
+      new DBColumnInfo(cluster_handle_dummy, Long.class, null, null, true));
+
+    Statement statement = null;
+    ResultSet resultSet = null;
+
+    try {
+      statement = dbAccessor.getConnection().createStatement();
+      if (statement != null) {
+        String selectSQL = String.format("SELECT cluster_id, cluster_name FROM %s",
+          CLUSTER_TABLE);
+
+        resultSet = statement.executeQuery(selectSQL);
+        while (null != resultSet && resultSet.next()) {
+          final Long clusterId = resultSet.getLong("cluster_id");
+          final String clusterName = resultSet.getString("cluster_name");
+
+          String updateSQL = String.format(
+            "UPDATE %s SET %s = %d WHERE cluster_handle = '%s'",
+            VIEWINSTANCE_TABLE, cluster_handle_dummy, clusterId, clusterName);
+
+          dbAccessor.executeQuery(updateSQL);
+        }
+      }
+    } finally {
+      JdbcUtils.closeResultSet(resultSet);
+      JdbcUtils.closeStatement(statement);
+    }
+
+    dbAccessor.dropColumn(VIEWINSTANCE_TABLE, CLUSTER_HANDLE_COLUMN);
+    dbAccessor.renameColumn(VIEWINSTANCE_TABLE, cluster_handle_dummy,
+      new DBColumnInfo(CLUSTER_HANDLE_COLUMN, Long.class, null, null, true));
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/utils/MapUtils.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/MapUtils.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/MapUtils.java
new file mode 100644
index 0000000..25a6857
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/MapUtils.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     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.ambari.server.utils;
+
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MapUtils {
+  public static Map<String, String> fillMap(String fileName)  {
+    String line = null;
+    Map<String, String>  map = new HashMap<>();
+
+    try {
+      BufferedReader reader = new BufferedReader(new FileReader(new File(fileName)));
+      while ((line = reader.readLine()) != null) {
+        if (line.contains("=")) {
+          String[] strings = line.split("=");
+          map.put(strings[0], strings[1]);
+        }
+      }
+    } catch (Exception e) {
+
+    }
+    return map;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java
index 38a47a4..c0c887f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/RemoteAmbariClusterRegistry.java
@@ -46,11 +46,11 @@ public class RemoteAmbariClusterRegistry {
   @Inject
   private Configuration configuration;
 
-  public RemoteAmbariCluster get(String clusterName){
-    RemoteAmbariCluster remoteAmbariCluster = clusterMap.get(clusterName);
+  public RemoteAmbariCluster get(Long clusterId){
+    RemoteAmbariCluster remoteAmbariCluster = clusterMap.get(clusterId);
     if(remoteAmbariCluster == null){
-      RemoteAmbariCluster cluster = getCluster(clusterName);
-      RemoteAmbariCluster oldCluster = clusterMap.putIfAbsent(clusterName, cluster);
+      RemoteAmbariCluster cluster = getCluster(clusterId);
+      RemoteAmbariCluster oldCluster = clusterMap.putIfAbsent(cluster.getName(), cluster);
       if(oldCluster == null) remoteAmbariCluster = cluster;
       else remoteAmbariCluster = oldCluster;
     }
@@ -58,8 +58,8 @@ public class RemoteAmbariClusterRegistry {
   }
 
 
-  private RemoteAmbariCluster getCluster(String clusterName) {
-    RemoteAmbariClusterEntity remoteAmbariClusterEntity = remoteAmbariClusterDAO.findByName(clusterName);
+  private RemoteAmbariCluster getCluster(Long clusterId) {
+    RemoteAmbariClusterEntity remoteAmbariClusterEntity = remoteAmbariClusterDAO.findById(clusterId);
     RemoteAmbariCluster remoteAmbariCluster = new RemoteAmbariCluster(remoteAmbariClusterEntity, configuration);
     return remoteAmbariCluster;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
index e98a4cd..f1d5c35 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
@@ -307,7 +307,7 @@ public class ViewContextImpl implements ViewContext, ViewController {
   @Override
   public AmbariStreamProvider getAmbariClusterStreamProvider() {
 
-    String clusterHandle = viewInstanceEntity.getClusterHandle();
+    Long clusterHandle = viewInstanceEntity.getClusterHandle();
     ClusterType clusterType = viewInstanceEntity.getClusterType();
 
     AmbariStreamProvider clusterStreamProvider = null;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
index 6d4ef82..9f0a8d3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
@@ -33,6 +33,7 @@ import org.apache.ambari.server.api.resources.ViewExternalSubResourceDefinition;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.ViewExternalSubResourceService;
 import org.apache.ambari.server.api.services.ViewSubResourceService;
+import org.apache.ambari.server.api.util.ApiVersion;
 import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.AmbariServer;
@@ -911,7 +912,7 @@ public class ViewRegistry {
    */
   public Cluster getCluster(ViewInstanceDefinition viewInstance) {
     if (viewInstance != null) {
-      String clusterId = viewInstance.getClusterHandle();
+      Long clusterId = viewInstance.getClusterHandle();
 
       if (clusterId != null && viewInstance.getClusterType() == ClusterType.LOCAL_AMBARI) {
         try {
@@ -958,7 +959,7 @@ public class ViewRegistry {
 
             LOG.info("Auto creating instance of view " + viewName + " for cluster " + clusterName + ".");
             ViewInstanceEntity viewInstanceEntity = createViewInstanceEntity(viewEntity, viewConfig, autoConfig);
-            viewInstanceEntity.setClusterHandle(clusterName);
+            viewInstanceEntity.setClusterHandle(clusterId);
             installViewInstance(viewInstanceEntity);
           }
         } catch (Exception e) {
@@ -1205,7 +1206,7 @@ public class ViewRegistry {
     ViewContext viewInstanceContext = new ViewContextImpl(viewInstanceDefinition, this);
 
     ViewExternalSubResourceService externalSubResourceService =
-        new ViewExternalSubResourceService(viewDefinition.getExternalResourceType(), viewInstanceDefinition);
+        new ViewExternalSubResourceService(ApiVersion.v1, viewDefinition.getExternalResourceType(), viewInstanceDefinition);
 
     viewInstanceDefinition.addService(ResourceConfig.EXTERNAL_RESOURCE_PLURAL_NAME, externalSubResourceService);
 
@@ -1215,7 +1216,7 @@ public class ViewRegistry {
       Resource.Type  type           = resourceDefinition.getType();
       ResourceConfig resourceConfig = resourceDefinition.getResourceConfiguration();
 
-      ViewResourceHandler viewResourceService = new ViewSubResourceService(type, viewInstanceDefinition);
+      ViewResourceHandler viewResourceService = new ViewSubResourceService(ApiVersion.v1, type, viewInstanceDefinition);
 
       ClassLoader cl = viewDefinition.getClassLoader();
 
@@ -1681,6 +1682,7 @@ public class ViewRegistry {
     for (org.apache.ambari.server.state.Cluster cluster : allClusters.values()) {
 
       String clusterName = cluster.getClusterName();
+      Long clusterId= cluster.getClusterId();
       StackId stackId = cluster.getCurrentStackVersion();
       Set<String> serviceNames = cluster.getServices().keySet();
 
@@ -1690,7 +1692,7 @@ public class ViewRegistry {
           if (checkAutoInstanceConfig(autoInstanceConfig, stackId, service, serviceNames)) {
             LOG.info("Auto creating instance of view " + viewName + " for cluster " + clusterName + ".");
             ViewInstanceEntity viewInstanceEntity = createViewInstanceEntity(viewEntity, viewConfig, autoInstanceConfig);
-            viewInstanceEntity.setClusterHandle(clusterName);
+            viewInstanceEntity.setClusterHandle(clusterId);
             installViewInstance(viewInstanceEntity);
             addClusterInheritedPermissions(viewInstanceEntity, permissions);
           }
@@ -1907,11 +1909,11 @@ public class ViewRegistry {
   /**
    * Get Remote Ambari Cluster Stream provider
    *
-   * @param clusterName
+   * @param clusterId
    * @return
    */
-  protected AmbariStreamProvider createRemoteAmbariStreamProvider(String clusterName){
-    RemoteAmbariClusterEntity clusterEntity = remoteAmbariClusterDAO.findByName(clusterName);
+  protected AmbariStreamProvider createRemoteAmbariStreamProvider(Long clusterId){
+    RemoteAmbariClusterEntity clusterEntity = remoteAmbariClusterDAO.findById(clusterId);
     if(clusterEntity != null) {
       return new RemoteAmbariStreamProvider(getBaseurl(clusterEntity.getUrl()),
         clusterEntity.getUsername(),clusterEntity.getPassword(),

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
index 31dd8f2..e0c059e 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
@@ -123,8 +123,21 @@ CREATE TABLE serviceconfigmapping (
   CONSTRAINT FK_scvm_config FOREIGN KEY (config_id) REFERENCES clusterconfig(config_id),
   CONSTRAINT FK_scvm_scv FOREIGN KEY (service_config_id) REFERENCES serviceconfig(service_config_id));
 
+CREATE TABLE clusterservicegroups (
+  service_group_name VARCHAR(255) NOT NULL,
+  service_group_display_name VARCHAR(255) NOT NULL,
+  cluster_id BIGINT NOT NULL,
+  service_group_type VARCHAR(255) NOT NULL DEFAULT 'AMBARI',
+  assembly_file MEDIUMTEXT,
+  current_state VARCHAR(255) NOT NULL,
+  desired_state VARCHAR(255) NOT NULL,
+  CONSTRAINT PK_clusterservicegroups PRIMARY KEY (service_group_name, cluster_id),
+  CONSTRAINT FK_clusterservicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+
 CREATE TABLE clusterservices (
   service_name VARCHAR(255) NOT NULL,
+  stack_service_name VARCHAR(255) NOT NULL,
+  service_group_name VARCHAR(255) NOT NULL,
   cluster_id BIGINT NOT NULL,
   service_enabled INTEGER NOT NULL,
   CONSTRAINT PK_clusterservices PRIMARY KEY (service_name, cluster_id),
@@ -175,6 +188,7 @@ CREATE TABLE servicecomponentdesiredstate (
   desired_version VARCHAR(255) NOT NULL DEFAULT 'UNKNOWN',
   service_name VARCHAR(255) NOT NULL,
   recovery_enabled SMALLINT NOT NULL DEFAULT 0,
+  desired_count INTEGER NOT NULL DEFAULT 0,
   CONSTRAINT pk_sc_desiredstate PRIMARY KEY (id),
   CONSTRAINT unq_scdesiredstate_name UNIQUE(component_name, service_name, cluster_id),
   CONSTRAINT FK_scds_desired_stack_id FOREIGN KEY (desired_stack_id) REFERENCES stack(stack_id),
@@ -566,7 +580,7 @@ CREATE TABLE viewinstance (
   icon64 VARCHAR(255),
   xml_driven CHAR(1),
   alter_names SMALLINT NOT NULL DEFAULT 1,
-  cluster_handle VARCHAR(255),
+  cluster_handle BIGINT,
   cluster_type VARCHAR(100) NOT NULL DEFAULT 'LOCAL_AMBARI',
   short_url BIGINT,
   CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index 3c4f1ca..98dfd38 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -64,6 +64,7 @@ CREATE TABLE clusterconfig (
   version_tag VARCHAR(100) NOT NULL,
   version BIGINT NOT NULL,
   type_name VARCHAR(100) NOT NULL,
+  stack_type_name VARCHAR(100) NOT NULL,
   cluster_id BIGINT NOT NULL,
   stack_id BIGINT NOT NULL,
   config_data LONGTEXT NOT NULL,
@@ -123,8 +124,21 @@ CREATE TABLE serviceconfigmapping (
   CONSTRAINT FK_scvm_config FOREIGN KEY (config_id) REFERENCES clusterconfig(config_id),
   CONSTRAINT FK_scvm_scv FOREIGN KEY (service_config_id) REFERENCES serviceconfig(service_config_id));
 
+CREATE TABLE clusterservicegroups (
+  service_group_name VARCHAR(255) NOT NULL,
+  service_group_display_name VARCHAR(255) NOT NULL,
+  cluster_id BIGINT NOT NULL,
+  service_group_type VARCHAR(255) NOT NULL DEFAULT 'AMBARI',
+  assembly_file MEDIUMTEXT,
+  current_state VARCHAR(255) NOT NULL,
+  desired_state VARCHAR(255) NOT NULL,
+  CONSTRAINT PK_clusterservicegroups PRIMARY KEY (service_group_name, cluster_id),
+  CONSTRAINT FK_clusterservicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+
 CREATE TABLE clusterservices (
   service_name VARCHAR(255) NOT NULL,
+  stack_service_name VARCHAR(255) NOT NULL,
+  service_group_name VARCHAR(255) NOT NULL,
   cluster_id BIGINT NOT NULL,
   service_enabled INTEGER NOT NULL,
   CONSTRAINT PK_clusterservices PRIMARY KEY (service_name, cluster_id),
@@ -175,6 +189,7 @@ CREATE TABLE servicecomponentdesiredstate (
   desired_state VARCHAR(255) NOT NULL,
   service_name VARCHAR(100) NOT NULL,
   recovery_enabled SMALLINT NOT NULL DEFAULT 0,
+  desired_count INTEGER NOT NULL DEFAULT 0,
   CONSTRAINT pk_sc_desiredstate PRIMARY KEY (id),
   CONSTRAINT unq_scdesiredstate_name UNIQUE(component_name, service_name, cluster_id),
   CONSTRAINT FK_scds_desired_stack_id FOREIGN KEY (desired_stack_id) REFERENCES stack(stack_id),
@@ -574,7 +589,7 @@ CREATE TABLE viewinstance (
   icon64 VARCHAR(255),
   xml_driven CHAR(1),
   alter_names TINYINT(1) NOT NULL DEFAULT 1,
-  cluster_handle VARCHAR(255),
+  cluster_handle BIGINT,
   cluster_type VARCHAR(100) NOT NULL DEFAULT 'LOCAL_AMBARI',
   short_url BIGINT,
   CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index f31af16..d3d2e76 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -54,6 +54,7 @@ CREATE TABLE clusterconfig (
   version_tag VARCHAR2(255) NOT NULL,
   version NUMBER(19) NOT NULL,
   type_name VARCHAR2(255) NOT NULL,
+  stack_type_name VARCHAR2(255) NOT NULL,
   cluster_id NUMBER(19) NOT NULL,
   stack_id NUMBER(19) NOT NULL,
   config_data CLOB NOT NULL,
@@ -114,8 +115,21 @@ CREATE TABLE serviceconfigmapping (
   CONSTRAINT FK_scvm_config FOREIGN KEY (config_id) REFERENCES clusterconfig(config_id),
   CONSTRAINT FK_scvm_scv FOREIGN KEY (service_config_id) REFERENCES serviceconfig(service_config_id));
 
+CREATE TABLE clusterservicegroups (
+  service_group_name VARCHAR(255) NOT NULL,
+  service_group_display_name VARCHAR(255) NOT NULL,
+  cluster_id BIGINT NOT NULL,
+  service_group_type VARCHAR(255) NOT NULL DEFAULT 'AMBARI',
+  assembly_file CLOB,
+  current_state VARCHAR(255) NOT NULL,
+  desired_state VARCHAR(255) NOT NULL,
+  CONSTRAINT PK_clusterservicegroups PRIMARY KEY (service_group_name, cluster_id),
+  CONSTRAINT FK_clusterservicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+
 CREATE TABLE clusterservices (
   service_name VARCHAR2(255) NOT NULL,
+  stack_service_name VARCHAR(255) NOT NULL,
+  service_group_name VARCHAR(255) NOT NULL,
   cluster_id NUMBER(19) NOT NULL,
   service_enabled NUMBER(10) NOT NULL,
   CONSTRAINT PK_clusterservices PRIMARY KEY (service_name, cluster_id),
@@ -166,6 +180,7 @@ CREATE TABLE servicecomponentdesiredstate (
   desired_version VARCHAR(255) DEFAULT 'UNKNOWN' NOT NULL,
   service_name VARCHAR2(255) NOT NULL,
   recovery_enabled SMALLINT DEFAULT 0 NOT NULL,
+  desired_count INTEGER NOT NULL DEFAULT 0,
   CONSTRAINT pk_sc_desiredstate PRIMARY KEY (id),
   CONSTRAINT unq_scdesiredstate_name UNIQUE(component_name, service_name, cluster_id),
   CONSTRAINT FK_scds_desired_stack_id FOREIGN KEY (desired_stack_id) REFERENCES stack(stack_id),
@@ -565,7 +580,7 @@ CREATE TABLE viewinstance (
   icon64 VARCHAR(255),
   xml_driven CHAR(1),
   alter_names NUMBER(1) DEFAULT 1 NOT NULL,
-  cluster_handle VARCHAR(255),
+  cluster_handle BIGINT,
   cluster_type VARCHAR(100) DEFAULT 'LOCAL_AMBARI' NOT NULL,
   short_url NUMBER,
   CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index d1147b7..e591975 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -54,6 +54,7 @@ CREATE TABLE clusterconfig (
   version_tag VARCHAR(255) NOT NULL,
   version BIGINT NOT NULL,
   type_name VARCHAR(255) NOT NULL,
+  stack_type_name VARCHAR(255) NOT NULL,
   cluster_id BIGINT NOT NULL,
   stack_id BIGINT NOT NULL,
   config_data TEXT NOT NULL,
@@ -123,8 +124,21 @@ CREATE TABLE serviceconfigmapping (
   CONSTRAINT FK_scvm_config FOREIGN KEY (config_id) REFERENCES clusterconfig(config_id),
   CONSTRAINT FK_scvm_scv FOREIGN KEY (service_config_id) REFERENCES serviceconfig(service_config_id));
 
+CREATE TABLE clusterservicegroups (
+  service_group_name VARCHAR(255) NOT NULL,
+  service_group_display_name VARCHAR(255) NOT NULL,
+  cluster_id BIGINT NOT NULL,
+  service_group_type VARCHAR(255) NOT NULL DEFAULT 'AMBARI',
+  assembly_file TEXT,
+  current_state VARCHAR(255) NOT NULL,
+  desired_state VARCHAR(255) NOT NULL,
+  CONSTRAINT PK_clusterservicegroups PRIMARY KEY (service_group_name, cluster_id),
+  CONSTRAINT FK_clusterservicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+
 CREATE TABLE clusterservices (
   service_name VARCHAR(255) NOT NULL,
+  stack_service_name VARCHAR(255) NOT NULL,
+  service_group_name VARCHAR(100) DEFAULT 'CORE' NOT NULL,
   cluster_id BIGINT NOT NULL,
   service_enabled INTEGER NOT NULL,
   CONSTRAINT PK_clusterservices PRIMARY KEY (service_name, cluster_id),
@@ -175,6 +189,7 @@ CREATE TABLE servicecomponentdesiredstate (
   desired_state VARCHAR(255) NOT NULL,
   service_name VARCHAR(255) NOT NULL,
   recovery_enabled SMALLINT NOT NULL DEFAULT 0,
+  desired_count INTEGER NOT NULL DEFAULT 0,
   CONSTRAINT pk_sc_desiredstate PRIMARY KEY (id),
   CONSTRAINT unq_scdesiredstate_name UNIQUE(component_name, service_name, cluster_id),
   CONSTRAINT FK_scds_desired_stack_id FOREIGN KEY (desired_stack_id) REFERENCES stack(stack_id),
@@ -566,7 +581,7 @@ CREATE TABLE viewinstance (
   icon64 VARCHAR(255),
   xml_driven CHAR(1),
   alter_names SMALLINT NOT NULL DEFAULT 1,
-  cluster_handle VARCHAR(255),
+  cluster_handle BIGINT,
   cluster_type VARCHAR(100) NOT NULL DEFAULT 'LOCAL_AMBARI',
   short_url BIGINT,
   CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
index 5a7a6a5..087d8d8 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
@@ -73,6 +73,7 @@ CREATE TABLE ambari.clusterconfig (
   version_tag VARCHAR(255) NOT NULL,
   version BIGINT NOT NULL,
   type_name VARCHAR(255) NOT NULL,
+  stack_type_name VARCHAR(255) NOT NULL,
   cluster_id BIGINT NOT NULL,
   stack_id BIGINT NOT NULL,
   config_data TEXT NOT NULL,
@@ -154,8 +155,22 @@ CREATE TABLE ambari.serviceconfigmapping (
 );
 GRANT ALL PRIVILEGES ON TABLE ambari.serviceconfigmapping TO :username;
 
+CREATE TABLE ambari.clusterservicegroups (
+  service_group_name VARCHAR(255) NOT NULL,
+  service_group_display_name VARCHAR(255) NOT NULL,
+  cluster_id BIGINT NOT NULL,
+  service_group_type VARCHAR(255) NOT NULL DEFAULT 'AMBARI',
+  assembly_file TEXT,
+  current_state VARCHAR(255) NOT NULL,
+  desired_state VARCHAR(255) NOT NULL,
+  CONSTRAINT PK_clusterservicegroups PRIMARY KEY (service_group_name, cluster_id),
+  CONSTRAINT FK_clusterservicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+GRANT ALL PRIVILEGES ON TABLE ambari.clusterservicegroups TO :username;
+
 CREATE TABLE ambari.clusterservices (
   service_name VARCHAR(255) NOT NULL,
+  stack_service_name VARCHAR(255) NOT NULL,
+  service_group_name VARCHAR(255) NOT NULL,
   cluster_id BIGINT NOT NULL,
   service_enabled INTEGER NOT NULL,
   CONSTRAINT PK_clusterservices PRIMARY KEY (service_name, cluster_id),
@@ -214,6 +229,7 @@ CREATE TABLE ambari.servicecomponentdesiredstate (
   desired_state VARCHAR(255) NOT NULL,
   service_name VARCHAR(255) NOT NULL,
   recovery_enabled SMALLINT NOT NULL DEFAULT 0,
+  desired_count INTEGER NOT NULL DEFAULT 0,
   CONSTRAINT pk_sc_desiredstate PRIMARY KEY (id),
   CONSTRAINT unq_scdesiredstate_name UNIQUE(component_name, service_name, cluster_id),
   CONSTRAINT FK_scds_desired_stack_id FOREIGN KEY (desired_stack_id) REFERENCES ambari.stack(stack_id),
@@ -667,7 +683,7 @@ CREATE TABLE ambari.viewinstance (
   icon64 VARCHAR(255),
   xml_driven CHAR(1),
   alter_names SMALLINT NOT NULL DEFAULT 1,
-  cluster_handle VARCHAR(255),
+  cluster_handle BIGINT,
   cluster_type VARCHAR(100) NOT NULL DEFAULT 'LOCAL_AMBARI',
   short_url BIGINT,
   CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
index 2dba3b7..7e217fd 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
@@ -53,6 +53,7 @@ CREATE TABLE clusterconfig (
   version_tag VARCHAR(255) NOT NULL,
   version NUMERIC(19) NOT NULL,
   type_name VARCHAR(255) NOT NULL,
+  stack_type_name VARCHAR(255) NOT NULL,
   cluster_id NUMERIC(19) NOT NULL,
   stack_id NUMERIC(19) NOT NULL,
   config_data TEXT NOT NULL,
@@ -112,8 +113,21 @@ CREATE TABLE serviceconfigmapping (
   CONSTRAINT FK_scvm_config FOREIGN KEY (config_id) REFERENCES clusterconfig(config_id),
   CONSTRAINT FK_scvm_scv FOREIGN KEY (service_config_id) REFERENCES serviceconfig(service_config_id));
 
+CREATE TABLE clusterservicegroups (
+  service_group_name VARCHAR(255) NOT NULL,
+  service_group_display_name VARCHAR(255) NOT NULL,
+  cluster_id BIGINT NOT NULL,
+  service_group_type VARCHAR(255) NOT NULL DEFAULT 'AMBARI',
+  assembly_file TEXT,
+  current_state VARCHAR(255) NOT NULL,
+  desired_state VARCHAR(255) NOT NULL,
+  CONSTRAINT PK_clusterservicegroups PRIMARY KEY (service_group_name, cluster_id),
+  CONSTRAINT FK_clusterservicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+
 CREATE TABLE clusterservices (
   service_name VARCHAR(255) NOT NULL,
+  stack_service_name VARCHAR(255) NOT NULL,
+  service_group_name VARCHAR(255) NOT NULL,
   cluster_id NUMERIC(19) NOT NULL,
   service_enabled INTEGER NOT NULL,
   CONSTRAINT PK_clusterservices PRIMARY KEY (service_name, cluster_id),
@@ -164,6 +178,7 @@ CREATE TABLE servicecomponentdesiredstate (
   desired_state VARCHAR(255) NOT NULL,
   service_name VARCHAR(255) NOT NULL,
   recovery_enabled SMALLINT NOT NULL DEFAULT 0,
+  desired_count INTEGER NOT NULL DEFAULT 0,
   CONSTRAINT pk_sc_desiredstate PRIMARY KEY (id),
   CONSTRAINT unq_scdesiredstate_name UNIQUE(component_name, service_name, cluster_id),
   CONSTRAINT FK_scds_desired_stack_id FOREIGN KEY (desired_stack_id) REFERENCES stack(stack_id),
@@ -563,7 +578,7 @@ CREATE TABLE viewinstance (
   icon64 VARCHAR(255),
   xml_driven CHAR(1),
   alter_names BIT NOT NULL DEFAULT 1,
-  cluster_handle VARCHAR(255),
+  cluster_handle BIGINT,
   cluster_type VARCHAR(100) NOT NULL DEFAULT 'LOCAL_AMBARI',
   short_url NUMERIC,
   CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
index e769e5b..045b5b1 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -67,6 +67,7 @@ CREATE TABLE clusterconfig (
   version_tag VARCHAR(255) NOT NULL,
   version BIGINT NOT NULL,
   type_name VARCHAR(255) NOT NULL,
+  stack_type_name VARCHAR(255) NOT NULL,
   cluster_id BIGINT NOT NULL,
   stack_id BIGINT NOT NULL,
   config_data VARCHAR(MAX) NOT NULL,
@@ -136,8 +137,21 @@ CREATE TABLE clusterconfigmapping (
   CONSTRAINT PK_clusterconfigmapping PRIMARY KEY CLUSTERED (cluster_id, type_name, create_timestamp ),
   CONSTRAINT clusterconfigmappingcluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
 
+CREATE TABLE clusterservicegroups (
+  service_group_name VARCHAR(255) NOT NULL,
+  service_group_display_name VARCHAR(255) NOT NULL,
+  cluster_id BIGINT NOT NULL,
+  service_group_type VARCHAR(255) NOT NULL DEFAULT 'AMBARI',
+  assembly_file VARCHAR(MAX),
+  current_state VARCHAR(255) NOT NULL,
+  desired_state VARCHAR(255) NOT NULL,
+  CONSTRAINT PK_clusterservicegroups PRIMARY KEY (service_group_name, cluster_id),
+  CONSTRAINT FK_clusterservicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
+
 CREATE TABLE clusterservices (
   service_name VARCHAR(255) NOT NULL,
+  stack_service_name VARCHAR(255) NOT NULL,
+  service_group_name VARCHAR(255) NOT NULL,
   cluster_id BIGINT NOT NULL,
   service_enabled INT NOT NULL,
   CONSTRAINT PK_clusterservices PRIMARY KEY CLUSTERED (service_name, cluster_id),
@@ -188,6 +202,7 @@ CREATE TABLE servicecomponentdesiredstate (
   desired_state VARCHAR(255) NOT NULL,
   service_name VARCHAR(255) NOT NULL,
   recovery_enabled SMALLINT NOT NULL DEFAULT 0,
+  desired_count INTEGER NOT NULL DEFAULT 0,
   CONSTRAINT pk_sc_desiredstate PRIMARY KEY (id),
   CONSTRAINT unq_scdesiredstate_name UNIQUE(component_name, service_name, cluster_id),
   CONSTRAINT FK_scds_desired_stack_id FOREIGN KEY (desired_stack_id) REFERENCES stack(stack_id),
@@ -573,7 +588,7 @@ CREATE TABLE viewinstance (
   icon64 VARCHAR(255),
   xml_driven CHAR(1),
   alter_names BIT NOT NULL DEFAULT 1,
-  cluster_handle VARCHAR(255),
+  cluster_handle BIGINT,
   cluster_type VARCHAR(100) NOT NULL DEFAULT 'LOCAL_AMBARI',
   short_url BIGINT,
   CONSTRAINT PK_viewinstance PRIMARY KEY CLUSTERED (view_instance_id),

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/META-INF/persistence.xml b/ambari-server/src/main/resources/META-INF/persistence.xml
index 5671dcf..46f3c5a 100644
--- a/ambari-server/src/main/resources/META-INF/persistence.xml
+++ b/ambari-server/src/main/resources/META-INF/persistence.xml
@@ -27,6 +27,7 @@
     <class>org.apache.ambari.server.orm.entities.ClusterConfigMappingEntity</class>
     <class>org.apache.ambari.server.orm.entities.ClusterEntity</class>
     <class>org.apache.ambari.server.orm.entities.ClusterServiceEntity</class>
+    <class>org.apache.ambari.server.orm.entities.ClusterServiceGroupEntity</class>
     <class>org.apache.ambari.server.orm.entities.ClusterStateEntity</class>
     <class>org.apache.ambari.server.orm.entities.ClusterVersionEntity</class>
     <class>org.apache.ambari.server.orm.entities.ConfigGroupConfigMappingEntity</class>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/ambari-server/src/main/resources/ambari.repo
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/ambari.repo b/ambari-server/src/main/resources/ambari.repo
new file mode 100644
index 0000000..5a58d49
--- /dev/null
+++ b/ambari-server/src/main/resources/ambari.repo
@@ -0,0 +1,8 @@
+#VERSION_NUMBER=2.4.0.0-583
+[AMBARI.2.4.0.0-2.x]
+name=Ambari 2.x
+baseurl=http://s3.amazonaws.com/dev.hortonworks.com/ambari/centos6/2.x/BUILDS/2.4.0.0-583/
+gpgcheck=1
+gpgkey=http://s3.amazonaws.com/dev.hortonworks.com/ambari/centos6/RPM-GPG-KEY/RPM-GPG-KEY-Jenkins
+enabled=1
+priority=1